﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ПрограммныйИнтерфейс

#Область ИнициализацияОбмена

// Добавляет строку в таблицу правил конвертации и инициализирует значение в колонке "Свойства".
// Используется в модуле менеджера обмена при заполнении таблицы правил конвертации объектов.
//
// Параметры:
//  ПравилаКонвертации - см. КоллекцияПравилКонвертации
//
// Возвращаемое значение:
//  СтрокаТаблицыЗначений - строка таблицы правил конвертации.
//
Функция ИнициализироватьПравилоКонвертацииОбъекта(ПравилаКонвертации) Экспорт
	
	ПравилоКонвертации = ПравилаКонвертации.Добавить();
	ПравилоКонвертации.Свойства = ИнициализироватьТаблицуСвойствДляПравилаКонвертации();
	Возврат ПравилоКонвертации;
	
КонецФункции

// Инициализирует компоненты обмена.
//
// Параметры:
//  НаправлениеОбмена - Строка - направление выполнения обмена: "Отправка" | "Получение".
//
// Возвращаемое значение:
//   Структура - содержит компоненты обмена (правила обмена и параметры обмена):
//     * ВерсияФорматаОбмена - Строка - номер версии формата обмена.
//     * XMLСхема - Строка - пространство имен формата обмена.
//     * МенеджерОбмена - ОбщийМодуль - модуль с правилами конвертации.
//     * УзелКорреспондента - ПланОбменаСсылка - ссылка на узел плана обмена.
//     * УзелКорреспондентаОбъект - ПланОбменаОбъект - объект узла плана обмена.
//     * ВерсияФорматаМенеджераОбмена - Строка - номер версии формата модуля с правилами конвертации.
//     * НаправлениеОбмена - Строка - "Отправка" или "Получение".
//     * ЭтоОбменЧерезПланОбмена - Булево - признак выполнения обмена по плану обмена.
//     * ФлагОшибки - Булево - признак наличия ошибки при выполнении действия обмена.
//     * СтрокаСообщенияОбОшибке - Строка - описание ошибки при выполнении действия обмена.
//     * КлючСообщенияЖурналаРегистрации - Строка - имя события для записи информации об ошибках в журнал регистрации.
//     * ИспользоватьКвитирование - Булево - признак использования квитирования для удаления регистрации изменений.
//     * ВыгруженныеОбъекты - Массив из ЛюбаяСсылка - коллекция выгруженных объектов.
//     * НеВыгруженныеОбъекты - Массив из ЛюбаяСсылка - коллекция не выгруженных объектов.
//     * ВыгруженныеПоСсылкеОбъекты - Массив из ЛюбаяСсылка - коллекция объектов, выгруженных "по ссылке".
//     * ДокументыДляОтложенногоПроведения - ТаблицаЗначений - коллекция документов для отложенного проведения:
//       ** ДокументСсылка - ДокументСсылка - ссылка на документ.
//       ** ДатаДокумента - Дата - дата документа.
//     * ПоддерживаемыеОбъектыXDTO - Массив из Строка - коллекция идентификаторов объектов формата.
//     * ЗагруженныеОбъекты - ТаблицаЗначений - коллекция загруженных объектов:
//       ** ИмяОбработчика - Строка - имя обработчика.
//       ** Объект - СправочникОбъект
//                 - ДокументОбъект - загруженный объект.
//       ** Параметры - Произвольный - произвольные параметры.
//       ** СсылкаНаОбъект - ЛюбаяСсылка - ссылка на загруженный объект.
//     * ПравилаОбработкиДанных - см. ТаблицаПравилОбработкиДанных
//     * СостояниеОбменаДанными - Структура - описание состояния выполнения обмена:
//       ** УзелИнформационнойБазы - ПланОбменаСсылка - узел плана обмена.
//       ** ДействиеПриОбмене - ПеречислениеСсылка.ДействияПриОбмене - выполняемое действие.
//       ** ДатаНачала - Дата - дата начала выполнения действия.
//       ** ДатаОкончания - Дата - дата окончания выполнения действия.
//       ** РезультатВыполненияОбмена - ПеречислениеСсылка.РезультатыВыполненияОбмена
//                                    - Неопределено - результат
//           выполнения действия.
//     * ТаблицаДанныхЗаголовкаПакета - см. НоваяТаблицаДанныхЗаголовкаПакета
// 
Функция ИнициализироватьКомпонентыОбмена(НаправлениеОбмена) Экспорт
	
	КомпонентыОбмена = Новый Структура;
	КомпонентыОбмена.Вставить("ВерсияФорматаОбмена");
	КомпонентыОбмена.Вставить("XMLСхема");
	КомпонентыОбмена.Вставить("МенеджерОбмена");
	
	КомпонентыОбмена.Вставить("СхемаРасширенияФормата");
	КомпонентыОбмена.Вставить("РасширенияФормата", Новый Соответствие);
	
	КомпонентыОбмена.Вставить("УзелКорреспондента");
	КомпонентыОбмена.Вставить("УзелКорреспондентаОбъект");
	КомпонентыОбмена.Вставить("ВерсияФорматаМенеджераОбмена");
		
	КомпонентыОбмена.Вставить("НаправлениеОбмена", НаправлениеОбмена);
	КомпонентыОбмена.Вставить("ЭтоОбменЧерезПланОбмена", Истина);
	КомпонентыОбмена.Вставить("ФлагОшибки", Ложь);
	КомпонентыОбмена.Вставить("СтрокаСообщенияОбОшибке", "");
	КомпонентыОбмена.Вставить("КлючСообщенияЖурналаРегистрации", ОбменДаннымиСервер.СобытиеЖурналаРегистрацииОбменДанными());
	КомпонентыОбмена.Вставить("ИспользоватьКвитирование", Истина);
	
	КомпонентыОбмена.Вставить("ОбменДаннымиСВнешнейСистемой", Ложь);
	КомпонентыОбмена.Вставить("ИдентификаторКорреспондента",  "");
	
	КомпонентыОбмена.Вставить("ТолькоНастройкиXDTO", Ложь);
	// Перечень поддерживаемых объектов формата для текущего сеанса обмена.
	// Содержит набор совместно поддерживаемых объектов этой базы и базы корреспондента
	// в контексте конкретного действия обмена (отправки/получения).
	// Подробнее см. ОбменДаннымиXDTOСервер.ЗаполнитьПоддерживаемыеОбъектыXDTO
	КомпонентыОбмена.Вставить("ПоддерживаемыеОбъектыXDTO", Новый Массив);
	
	СостояниеОбменаДанными = Новый Структура;
	СостояниеОбменаДанными.Вставить("УзелИнформационнойБазы");
	СостояниеОбменаДанными.Вставить("ДействиеПриОбмене");
	СостояниеОбменаДанными.Вставить("ДатаНачала", ТекущаяДатаСеанса());
	СостояниеОбменаДанными.Вставить("ДатаОкончания");
	СостояниеОбменаДанными.Вставить("РезультатВыполненияОбмена");
	КомпонентыОбмена.Вставить("СостояниеОбменаДанными", СостояниеОбменаДанными);
	
	ВедениеПротоколаДанных = Новый Структура;
	ВедениеПротоколаДанных.Вставить("ФайлПротоколаДанных", Неопределено);
	ВедениеПротоколаДанных.Вставить("ВыводВПротоколИнформационныхСообщений", Ложь);
	ВедениеПротоколаДанных.Вставить("ДописыватьДанныеВПротоколОбмена", Истина);
	
	КомпонентыОбмена.Вставить("ВедениеПротоколаДанных", ВедениеПротоколаДанных);
	
	КомпонентыОбмена.Вставить("ИспользоватьТранзакции", Истина);
	
	// Структура настроек XDTO этой базы.
	// Участвует в формировании списка поддерживаемых объектов (см. "ПоддерживаемыеОбъектыXDTO")
	// При отправке по ней будет сформирована заголовочная часть сообщения обмена - в этом случае
	// будет содержать перечень всех доступных объектов формата с детализацией по версиям.
	КомпонентыОбмена.Вставить("НастройкиXDTO", СтруктураНастроекXDTO());
	
	Если НаправлениеОбмена = "Отправка" Тогда
		
		КомпонентыОбмена.Вставить("ВыгруженныеОбъекты", Новый Массив);
		КомпонентыОбмена.Вставить("КоличествоОбъектовКВыгрузке", 0);
		КомпонентыОбмена.Вставить("СчетчикВыгруженныхОбъектов", 0);
		КомпонентыОбмена.Вставить("СоответствиеРегистрацияПоНеобходимости", Новый Соответствие);
		КомпонентыОбмена.Вставить("ВыгруженныеПоСсылкеОбъекты", Новый Массив);
		
		КомпонентыОбмена.Вставить("СценарийВыгрузки");
		
		КомпонентыОбмена.Вставить("ТаблицаПравилаРегистрацииОбъектов");
		КомпонентыОбмена.Вставить("СвойстваУзлаПланаОбмена");
		
		КомпонентыОбмена.Вставить("ПропускатьОбъектыСОшибкамиПроверкиПоСхеме", Ложь);
		КомпонентыОбмена.Вставить("НеВыгруженныеОбъекты", Новый Массив);
		
	Иначе
		
		КомпонентыОбмена.Вставить("НомерВходящегоСообщения");
		КомпонентыОбмена.Вставить("НомерСообщенияПолученногоКорреспондентом");
		
		КомпонентыОбмена.Вставить("РежимЗагрузкиДанныхВИнформационнуюБазу", Истина);
		КомпонентыОбмена.Вставить("СчетчикЗагруженныхОбъектов", 0);
		КомпонентыОбмена.Вставить("КоличествоОбъектовНаТранзакцию", 0);
		КомпонентыОбмена.Вставить("КоличествоОбъектовКЗагрузке", 0);
		КомпонентыОбмена.Вставить("РазмерФайлаСообщенияОбмена", 0);
		
		ДокументыДляОтложенногоПроведения = Новый ТаблицаЗначений;
		ДокументыДляОтложенногоПроведения.Колонки.Добавить("ДокументСсылка");
		ДокументыДляОтложенногоПроведения.Колонки.Добавить("ДатаДокумента", Новый ОписаниеТипов("Дата"));
		КомпонентыОбмена.Вставить("ДокументыДляОтложенногоПроведения", ДокументыДляОтложенногоПроведения);
		
		ЗагруженныеОбъекты = Новый ТаблицаЗначений;
		ЗагруженныеОбъекты.Колонки.Добавить("ИмяОбработчика");
		ЗагруженныеОбъекты.Колонки.Добавить("Объект");
		ЗагруженныеОбъекты.Колонки.Добавить("Параметры");
		ЗагруженныеОбъекты.Колонки.Добавить("СсылкаНаОбъект");
		ЗагруженныеОбъекты.Индексы.Добавить("СсылкаНаОбъект");
		КомпонентыОбмена.Вставить("ЗагруженныеОбъекты", ЗагруженныеОбъекты);
		
		ТаблицаОбъектовСозданныхПоСсылкам = Новый ТаблицаЗначений();
		ТаблицаОбъектовСозданныхПоСсылкам.Колонки.Добавить("СсылкаНаОбъект");
		ТаблицаОбъектовСозданныхПоСсылкам.Колонки.Добавить("УдалятьСозданныеПоКлючевымСвойствам");
		ТаблицаОбъектовСозданныхПоСсылкам.Индексы.Добавить("СсылкаНаОбъект");
		КомпонентыОбмена.Вставить("ТаблицаОбъектовСозданныхПоСсылкам", ТаблицаОбъектовСозданныхПоСсылкам);
		
		КомпонентыОбмена.Вставить("ТаблицаДанныхЗаголовкаПакета", НоваяТаблицаДанныхЗаголовкаПакета());
		КомпонентыОбмена.Вставить("ТаблицыДанныхСообщенияОбмена", Новый Соответствие);
		
		КомпонентыОбмена.Вставить("ОбъектыДляОтложеннойЗаписи", Новый Соответствие);
		
		// Структура настроек XDTO корреспондента, зачитываемая из сообщения обмена.
		КомпонентыОбмена.Вставить("НастройкиXDTOКорреспондента", СтруктураНастроекXDTO());
		
		КомпонентыОбмена.Вставить("ПрефиксКорреспондента");
		
		КомпонентыОбмена.Вставить("УдалятьСозданныеПоКлючевымСвойствам", Ложь);
		КомпонентыОбмена.Вставить("ПомеченныеНаУдалениеОбъекты",         Новый Массив);
		
	КонецЕсли;
	
	КомпонентыОбмена.Вставить("ВыполнятьЗамеры", Ложь);
	КомпонентыОбмена.Вставить("СеансОбмена", Неопределено);
	КомпонентыОбмена.Вставить("ИмяВременногоФайлаЗамеров", "");
	КомпонентыОбмена.Вставить("ЗаписьЗамеров", Неопределено);
	КомпонентыОбмена.Вставить("ТаблицаЗамеровПоСобытиям", ОбменДаннымиОценкаПроизводительности.ТаблицаЗамеровПоСобытиям());
	
	КомпонентыОбмена.Вставить("ИспользоватьКешПубличныхИдентификаторов", Ложь);
	КомпонентыОбмена.Вставить("КешПубличныхИдентификаторов", Неопределено);
	
	КомпонентыОбмена.Вставить("ОбменЧерезОбработкуВыгрузкаЗагрузкаED", Ложь);
	
	Возврат КомпонентыОбмена;
	
КонецФункции

// Инициализирует таблицы значений с правилами обмена и помещает их в КомпонентыОбмена.
//
// Параметры:
//  КомпонентыОбмена - Структура - содержит все правила и параметры обмена.
//
Процедура ИнициализироватьТаблицыПравилОбмена(КомпонентыОбмена) Экспорт
	
	КомпонентыОбмена.Вставить("БазовыеСхемыФормата", Новый Соответствие);
	КомпонентыОбмена.БазовыеСхемыФормата.Вставить(КомпонентыОбмена.XMLСхема, Истина);
	КомпонентыОбмена.БазовыеСхемыФормата.Вставить(XMLБазоваяСхема(), Истина);
	
	// Вычисление версии формата менеджера обмена - от этого зависит формирование правил.
	Попытка
		КомпонентыОбмена.Вставить("ВерсияФорматаМенеджераОбмена", КомпонентыОбмена.МенеджерОбмена.ВерсияФорматаМенеджераОбмена());
	Исключение
		КомпонентыОбмена.Вставить("ВерсияФорматаМенеджераОбмена", "1");
	КонецПопытки;
	
	// Инициализация таблиц правил обмена.
	КомпонентыОбмена.Вставить("ПравилаОбработкиДанных",     ТаблицаПравилОбработкиДанных(КомпонентыОбмена));
	КомпонентыОбмена.Вставить("ПравилаКонвертацииОбъектов", ТаблицаПравилКонвертации(КомпонентыОбмена));
	
	КомпонентыОбмена.Вставить("ПравилаКонвертацииПредопределенныхДанных", ТаблицаПравилКонвертацииПредопределенныхДанных(КомпонентыОбмена));
	
	КомпонентыОбмена.Вставить("ПараметрыКонвертации", СтруктураПараметровКонвертации(КомпонентыОбмена.МенеджерОбмена));
	
КонецПроцедуры

// Инициализирует таблицу значений для хранения правил конвертации свойств объекта.
//
// Возвращаемое значение:
//   ТаблицаЗначений - таблица для хранения правил конвертации свойств:
//     * СвойствоКонфигурации - Строка
//     * СвойствоФормата - Строка
//     * ПравилоКонвертацииСвойства - Строка
//     * ИспользуетсяАлгоритмКонвертации - Булево
//     * ОбработкаКлючевогоСвойства - Булево
//     * ОбработкаПоисковогоСвойства - Булево
//     * ИмяТЧ - Строка
//
Функция ИнициализироватьТаблицуСвойствДляПравилаКонвертации() Экспорт
	
	ТаблицаПКС = Новый ТаблицаЗначений;
	ТаблицаПКС.Колонки.Добавить("СвойствоКонфигурации", Новый ОписаниеТипов("Строка"));
	ТаблицаПКС.Колонки.Добавить("СвойствоФормата",      Новый ОписаниеТипов("Строка"));
	
	ТаблицаПКС.Колонки.Добавить("ПравилоКонвертацииСвойства",      Новый ОписаниеТипов("Строка",,Новый КвалификаторыСтроки(100)));
	ТаблицаПКС.Колонки.Добавить("ИспользуетсяАлгоритмКонвертации", Новый ОписаниеТипов("Булево"));
	
	ТаблицаПКС.Колонки.Добавить("ОбработкаКлючевогоСвойства",  Новый ОписаниеТипов("Булево"));
	ТаблицаПКС.Колонки.Добавить("ОбработкаПоисковогоСвойства", Новый ОписаниеТипов("Булево"));
	
	ТаблицаПКС.Колонки.Добавить("ИмяТЧ", Новый ОписаниеТипов("Строка"));
	
	ТаблицаПКС.Колонки.Добавить("ПространствоИмен", Новый ОписаниеТипов("Строка"));
	
	ТаблицаПКС.Индексы.Добавить("ПространствоИмен");

	Возврат ТаблицаПКС;
	
КонецФункции

// Заполняет колонку со свойствами табличных частей пустой таблицей значений с определенными колонками.
// Используется в текущем модуле, а также в модуле менеджера обмена при заполнении таблицы правил конвертации объектов.
//
// Параметры:
//  ПравилоКонвертации - СтрокаТаблицыЗначений - правило конвертации объектов.
//  ИмяКолонки - Строка - имя заполняемой колонки таблицы правил конвертации.
//
Процедура ИнициализироватьСвойстваТабличныхЧастей(ПравилоКонвертации, ИмяКолонки = "СвойстваТабличныхЧастей") Экспорт
	СвойстваТабличныхЧастей = Новый ТаблицаЗначений;
	СвойстваТабличныхЧастей.Колонки.Добавить("ТЧКонфигурации",          Новый ОписаниеТипов("Строка"));
	СвойстваТабличныхЧастей.Колонки.Добавить("ТЧФормата",               Новый ОписаниеТипов("Строка"));
	СвойстваТабличныхЧастей.Колонки.Добавить("Свойства",                Новый ОписаниеТипов("ТаблицаЗначений"));
	СвойстваТабличныхЧастей.Колонки.Добавить("ИспользуетсяАлгоритмКонвертации", Новый ОписаниеТипов("Булево"));
	
	СвойстваТабличныхЧастей.Колонки.Добавить("ПространствоИмен",        Новый ОписаниеТипов("Строка"));
	СвойстваТабличныхЧастей.Индексы.Добавить("ПространствоИмен");
	
	ПравилоКонвертации[ИмяКолонки] = СвойстваТабличныхЧастей;
КонецПроцедуры

#КонецОбласти

#Область ВедениеПротокола
// Создает объект для записи протокола обмена и помещает его в КомпонентыОбмена.
//
// Параметры:
//  КомпонентыОбмена        - Структура - содержит все правила и параметры обмена.
//  ИмяФайлаПротоколаОбмена - Строка - содержит полное имя файла протокола.
//
Процедура ИнициализироватьВедениеПротоколаОбмена(КомпонентыОбмена, ИмяФайлаПротоколаОбмена) Экспорт
	
	КомпонентыОбмена.ВедениеПротоколаДанных.ФайлПротоколаДанных = Неопределено;
	Если Не ПустаяСтрока(ИмяФайлаПротоколаОбмена) Тогда
		
		// Попытка записи в файл протокола обмена.
		Попытка
			КомпонентыОбмена.ВедениеПротоколаДанных.ФайлПротоколаДанных = Новый ЗаписьТекста(
				ИмяФайлаПротоколаОбмена,
				КодировкаТекста.UTF8,
				,
				КомпонентыОбмена.ВедениеПротоколаДанных.ДописыватьДанныеВПротоколОбмена);
		Исключение
			
			СтрокаСообщения = НСтр("ru = 'Ошибка при попытке записи в файл протокола данных: %1. Описание ошибки: %2'",
				ОбщегоНазначения.КодОсновногоЯзыка());
			СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения,
				ИмяФайлаПротоколаОбмена, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			
			ЗаписьЖурналаРегистрацииОбменДанными(СтрокаСообщения, КомпонентыОбмена, УровеньЖурналаРегистрации.Предупреждение);
			
		КонецПопытки;
		
	КонецЕсли;
	
КонецПроцедуры

// Завершает запись в протокол обмена.
//
// Параметры:
//  КомпонентыОбмена - Структура - содержит все правила и параметры обмена.
//
Процедура ЗавершитьВедениеПротоколаОбмена(КомпонентыОбмена) Экспорт
	
	Если КомпонентыОбмена.ВедениеПротоколаДанных.ФайлПротоколаДанных <> Неопределено Тогда
		
		КомпонентыОбмена.ВедениеПротоколаДанных.ФайлПротоколаДанных.Закрыть();
		КомпонентыОбмена.ВедениеПротоколаДанных.ФайлПротоколаДанных = Неопределено;
		
	КонецЕсли;
	
КонецПроцедуры

// Сохраняет в протокол выполнения (или выводит на экран) сообщения указанной структуры.
//
// Параметры:
//  КомпонентыОбмена - Структура - содержит все правила и параметры обмена.
//  КодОшибки        - Число
//                   - Строка
//                   - Структура - информация об ошибке.
//                       Число - код ошибки, см. ОбменДаннымиПовтИсп.СообщенияОбОшибках().
//                       Строка - описание ошибки.
//                       Структура - структура с кратким и подробным описанием ошибки:
//                         * КраткоеПредставлениеОшибки - описание ошибки для протокола (для пользователя).
//                         * ПодробноеПредставлениеОшибки - описание ошибки для журнала регистрации.
//                         * Уровень - УровеньЖурналаРегистрации - уровень важности ошибки.
//  СтруктураЗаписи   - Структура - структура записи протокола.
//  ВзвестиФлагОшибок - Булево - если истина, то - это сообщение об ошибке. Взводится ФлагОшибки.
//  Уровень           - Число - отступ слева, количество табуляций.
//  Выравнивание      - Число - отступ в тексте, для выравнивания текста выводимого в виде Ключ - Значение.
//  БезусловнаяЗаписьВПротоколОбмена - Булево - флаг безусловной записи информации в протокол.
//
// Возвращаемое значение:
//  Строка - текст ошибки, которая была записана в протокол.
//
Функция ЗаписатьВПротоколВыполнения(КомпонентыОбмена,
		КодОшибки = "",
		СтруктураЗаписи = Неопределено,
		ВзвестиФлагОшибок = Истина,
		Уровень = 0,
		Выравнивание = 22,
		БезусловнаяЗаписьВПротоколОбмена = Ложь) Экспорт
	
	ФайлПротоколаДанных = КомпонентыОбмена.ВедениеПротоколаДанных.ФайлПротоколаДанных;
	ВыводВПротоколИнформационныхСообщений = КомпонентыОбмена.ВедениеПротоколаДанных.ВыводВПротоколИнформационныхСообщений;
	
	Отступ = "";
	Для Сч = 0 По Уровень - 1 Цикл
		Отступ = Отступ + Символы.Таб;
	КонецЦикла; 
	
	КраткоеПредставлениеОшибки   = "";
	ПодробноеПредставлениеОшибки = "";
	
	Если ТипЗнч(КодОшибки) = Тип("Число") Тогда
		
		СообщенияОбОшибках = ОбменДаннымиПовтИсп.СообщенияОбОшибках();
		
		КраткоеПредставлениеОшибки   = СообщенияОбОшибках[КодОшибки];
		ПодробноеПредставлениеОшибки = СообщенияОбОшибках[КодОшибки];
		
	ИначеЕсли ТипЗнч(КодОшибки) = Тип("Структура") Тогда
		
		КодОшибки.Свойство("КраткоеПредставлениеОшибки",   КраткоеПредставлениеОшибки);
		КодОшибки.Свойство("ПодробноеПредставлениеОшибки", ПодробноеПредставлениеОшибки);
		
	Иначе
		
		КраткоеПредставлениеОшибки   = КодОшибки;
		ПодробноеПредставлениеОшибки = КодОшибки;
		
	КонецЕсли;

	КраткоеПредставлениеОшибки   = Отступ + Строка(КраткоеПредставлениеОшибки);
	ПодробноеПредставлениеОшибки = Отступ + Строка(ПодробноеПредставлениеОшибки);
	
	Если СтруктураЗаписи <> Неопределено Тогда
		
		Для Каждого Поле Из СтруктураЗаписи Цикл
			
			Значение = Поле.Значение;
			Если Значение = Неопределено Тогда
				Продолжить;
			КонецЕсли; 
			
			КраткоеПредставлениеОшибки  = КраткоеПредставлениеОшибки + Символы.ПС + Отступ + Символы.Таб
				+ СтроковыеФункцииКлиентСервер.ДополнитьСтроку(Поле.Ключ, Выравнивание, " ", "Справа") + " =  " + Строка(Значение);
			ПодробноеПредставлениеОшибки  = ПодробноеПредставлениеОшибки + Символы.ПС + Отступ + Символы.Таб
				+ СтроковыеФункцииКлиентСервер.ДополнитьСтроку(Поле.Ключ, Выравнивание, " ", "Справа") + " =  " + Строка(Значение);
			
		КонецЦикла;
		
	КонецЕсли;
	
	КомпонентыОбмена.СтрокаСообщенияОбОшибке = КраткоеПредставлениеОшибки;
	
	Если ВзвестиФлагОшибок Тогда
		
		КомпонентыОбмена.ФлагОшибки = Истина;
		Если КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена = Неопределено Тогда
			КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка;
		КонецЕсли;
		
	КонецЕсли;
	
	Если ФайлПротоколаДанных <> Неопределено Тогда
		
		Если ВзвестиФлагОшибок Тогда
			
			ФайлПротоколаДанных.ЗаписатьСтроку(Символы.ПС + "Ошибка.");
			
		КонецЕсли;
		
		Если ВзвестиФлагОшибок
			Или БезусловнаяЗаписьВПротоколОбмена
			Или ВыводВПротоколИнформационныхСообщений Тогда
			
			ФайлПротоколаДанных.ЗаписатьСтроку(Символы.ПС + КомпонентыОбмена.СтрокаСообщенияОбОшибке);
		
		КонецЕсли;
		
	КонецЕсли;
	
	УровеньЖР = Неопределено;
	Если Не ТипЗнч(КодОшибки) = Тип("Структура")
		Или Не КодОшибки.Свойство("Уровень", УровеньЖР)
		Или УровеньЖР = Неопределено Тогда
		
		Если РезультатВыполненияОбменаОшибка(КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена) Тогда
			УровеньЖР = УровеньЖурналаРегистрации.Ошибка;
		ИначеЕсли РезультатВыполненияОбменаПредупреждение(КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена) Тогда
			УровеньЖР = УровеньЖурналаРегистрации.Предупреждение;
		Иначе
			УровеньЖР = УровеньЖурналаРегистрации.Информация;
		КонецЕсли;
		
	КонецЕсли;
	
	ПозицияСсылки = СтрНайти(ПодробноеПредставлениеОшибки, "e1cib/data/");
	Если ПозицияСсылки > 0 Тогда
		ПозицияУИД = СтрНайти(ПодробноеПредставлениеОшибки, "?ref=");
		СтрокаСсылки = Сред(ПодробноеПредставлениеОшибки, ПозицияСсылки, ПозицияУИД - ПозицияСсылки + 37);
		ПерваяТочка = СтрНайти(СтрокаСсылки, "e1cib/data/");
		ВтораяТочка = СтрНайти(СтрокаСсылки, "?ref=");
		ПредставлениеТипа = Сред(СтрокаСсылки, ПерваяТочка + 11, ВтораяТочка - ПерваяТочка - 11);
		ШаблонЗначения = ЗначениеВСтрокуВнутр(ПредопределенноеЗначение(ПредставлениеТипа + ".ПустаяСсылка"));
		ЗначениеСсылки = СтрЗаменить(ШаблонЗначения, "00000000000000000000000000000000", Сред(СтрокаСсылки, ВтораяТочка + 5));
		СсылкаНаОбъект = ЗначениеИзСтрокиВнутр(ЗначениеСсылки);
	Иначе
		СсылкаНаОбъект = Неопределено;
	КонецЕсли;
	
	// Фиксируем событие в журнале регистрации.
	ЗаписьЖурналаРегистрацииОбменДанными(
		ПодробноеПредставлениеОшибки,
		КомпонентыОбмена,
		УровеньЖР,
		СсылкаНаОбъект);
	
	Возврат КомпонентыОбмена.СтрокаСообщенияОбОшибке;
	
КонецФункции

#КонецОбласти

#Область ПоискПравилОбмена
// Выполняет поиск правила конвертации объекта по имени.
//
// Параметры:
//  КомпонентыОбмена - Структура - содержит все правила и параметры обмена.
//  Имя              - Строка - имя правила.
//
// Возвращаемое значение:
//  СтрокаТаблицыЗначений - строка таблицы правил обмена, в которой содержится искомое правило.
//
Функция ПКОПоИмени(КомпонентыОбмена, Имя) Экспорт
	
	ПравилоКонвертации = КомпонентыОбмена.ПравилаКонвертацииОбъектов.Найти(Имя, "ИмяПКО");
	
	Если ПравилоКонвертации = Неопределено Тогда
		
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не найдено ПКО с именем %1'"), Имя);
			
	Иначе
		Возврат ПравилоКонвертации;
	КонецЕсли;

КонецФункции

#КонецОбласти

#Область ОтправкаДанных

// Выполняет выгрузку данных в соответствии с правилами и параметрами обмена.
//
// Параметры:
//  КомпонентыОбмена - см. ИнициализироватьКомпонентыОбмена
//
Процедура ПроизвестиВыгрузкуДанных(КомпонентыОбмена) Экспорт
	
	УзелДляОбмена = КомпонентыОбмена.УзелКорреспондента;
	
	Попытка
		
		ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
		
		КомпонентыОбмена.МенеджерОбмена.ПередКонвертацией(КомпонентыОбмена);
		
		ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
			ВремяНачала, "ПередКонвертацией", "", КомпонентыОбмена, 
			ОбменДаннымиОценкаПроизводительности.ТипСобытияПравило());
		
	Исключение
		
		ШаблонОписанияОшибки = НСтр("ru = 'Направление: %1.
			|Обработчик: %2.
			|
			|Ошибка выполнения обработчика.
			|%3.'");
		
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,
			КомпонентыОбмена.НаправлениеОбмена,
			"ПередКонвертацией",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		
		ВызватьИсключение ТекстОшибки;
			
	КонецПопытки;
	
	НомерОтправленного = 0;
	
	Если КомпонентыОбмена.ЭтоОбменЧерезПланОбмена Тогда
	
		НомерОтправленного = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(УзелДляОбмена, "НомерОтправленного") + 1;
		
		ВыполнитьВыгрузкуЗарегистрированныхДанных(КомпонентыОбмена, НомерОтправленного);
		
	Иначе
		
		Для Каждого Строка Из КомпонентыОбмена.СценарийВыгрузки Цикл
			ПравилоОбработки = ПОДПоИмени(КомпонентыОбмена, Строка.ИмяПОД);
			
			ВыборкаДанных = ВыборкаДанных(КомпонентыОбмена, ПравилоОбработки);
			Для Каждого ОбъектВыборки Из ВыборкаДанных Цикл
				ВыгрузкаОбъектаВыборки(КомпонентыОбмена, ОбъектВыборки, ПравилоОбработки);
			КонецЦикла;
		КонецЦикла;
		
	КонецЕсли;
	
	Если КомпонентыОбмена.ФлагОшибки Тогда
		
		// Объекты, которые выгружались по ссылкам кэшируются в регистре сведений ДанныеОбъектовДляРегистрацииВОбменах.
		// Для того, что бы при повторной выгрузке в файл сообщения попали не только ключевые сведения необходимо почистить регистр.
		Если КомпонентыОбмена.ВыгруженныеПоСсылкеОбъекты.Количество() > 0 Тогда
			
			РегистрыСведений.ДанныеОбъектовДляРегистрацииВОбменах.УдалитьСведенияОВыгрузкеОбъектов(КомпонентыОбмена.ВыгруженныеПоСсылкеОбъекты, КомпонентыОбмена.УзелКорреспондента);
			
		КонецЕсли;
		
		ВызватьИсключение НСтр("ru = 'При формировании сообщения обмена данными произошли ошибки. Подробнее см. в журнале регистрации.'");
		
	КонецЕсли;
	
	Попытка
		
		ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
		
		КомпонентыОбмена.МенеджерОбмена.ПослеКонвертации(КомпонентыОбмена);
		
		ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
			ВремяНачала, "ПослеКонвертации", "",КомпонентыОбмена,
			ОбменДаннымиОценкаПроизводительности.ТипСобытияПравило());
		
	Исключение
		
		ШаблонОписанияОшибки = НСтр("ru = 'Событие: %1.
				|Обработчик: %2.
				|
				|Ошибка выполнения обработчика.
				|%3.'");
		
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,
			КомпонентыОбмена.НаправлениеОбмена,
			"ПослеКонвертации",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			
		ВызватьИсключение ТекстОшибки;
		
	КонецПопытки;
	
	Если КомпонентыОбмена.ЭтоОбменЧерезПланОбмена Тогда
		
		// Сбрасываем номер отправленного сообщения у не выгруженных объектов.
		Если КомпонентыОбмена.ПропускатьОбъектыСОшибкамиПроверкиПоСхеме Тогда
			Для Каждого ОбъектСсылка Из КомпонентыОбмена.НеВыгруженныеОбъекты Цикл
				ПланыОбмена.ЗарегистрироватьИзменения(УзелДляОбмена, ОбъектСсылка);
			КонецЦикла;
		КонецЕсли;
		
		// Назначаем номер отправленного сообщения для объектов, выгруженных по ссылке.
		Если КомпонентыОбмена.ВыгруженныеПоСсылкеОбъекты.Количество() > 0 Тогда
			// Выполняем регистрацию объектов на текущем узле, которые были выгружены по ссылке.
			Для Каждого Элемент Из КомпонентыОбмена.ВыгруженныеПоСсылкеОбъекты Цикл
				ПланыОбмена.ЗарегистрироватьИзменения(УзелДляОбмена, Элемент);
			КонецЦикла;
			
			ОбменДаннымиСервер.ВыбратьИзменения(УзелДляОбмена, НомерОтправленного, КомпонентыОбмена.ВыгруженныеПоСсылкеОбъекты);
		КонецЕсли;
		
		НачатьТранзакцию();
		Попытка
		    Блокировка = Новый БлокировкаДанных;
		    ЭлементБлокировки = Блокировка.Добавить(ОбщегоНазначения.ИмяТаблицыПоСсылке(УзелДляОбмена));
		    ЭлементБлокировки.УстановитьЗначение("Ссылка", УзелДляОбмена);
		    Блокировка.Заблокировать();
		    
			ЗаблокироватьДанныеДляРедактирования(УзелДляОбмена);
			Получатель = УзелДляОбмена.ПолучитьОбъект();
			
			Получатель.НомерОтправленного = НомерОтправленного;
			Получатель.ОбменДанными.Загрузка = Истина;

			Получатель.Записать();

			ЗафиксироватьТранзакцию();
		Исключение
			ОтменитьТранзакцию();
			ВызватьИсключение;
		КонецПопытки;
		
	КонецЕсли;
	
	КомпонентыОбмена.ФайлОбмена.ЗаписатьКонецЭлемента(); // Body
	КомпонентыОбмена.ФайлОбмена.ЗаписатьКонецЭлемента(); // Message
	
	// Фиксация успешного завершения обмена.
	Если КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена = Неопределено Тогда
		КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Выполнено;
	КонецЕсли;
	
	Если КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Выполнено
		И (КомпонентыОбмена.ПропускатьОбъектыСОшибкамиПроверкиПоСхеме
			И КомпонентыОбмена.НеВыгруженныеОбъекты.Количество() > 0) Тогда
		КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.ВыполненоСПредупреждениями;
	КонецЕсли;
	
КонецПроцедуры

// Выполняет выгрузку объекта информационной базы.
//
// Параметры:
//   КомпонентыОбмена - см. ОбменДаннымиXDTOСервер.ИнициализироватьКомпонентыОбмена
//   Объект           - ЛюбаяСсылка - ссылка на объект информационной базы.
//   ПравилоОбработки - СтрокаТаблицыЗначений - строка таблицы правил обработки данных, 
//                      соответствующая правилу обработки типа выгружаемого объекта.
//                      Если параметр не задан, правило будет найдено по объекту метаданных выгружаемого объекта.
//
Процедура ВыгрузкаОбъектаВыборки(КомпонентыОбмена, Объект, ПравилоОбработки = Неопределено) Экспорт
	
	ОбъектСсылочногоТипа = (ТипЗнч(Объект) <> Тип("Структура"))
		И ОбщегоНазначения.ЭтоОбъектСсылочногоТипа(Объект.Метаданные());
		
	Если (ТипЗнч(Объект) <> Тип("Структура"))
		И ПравилоОбработки = Неопределено Тогда
		ПолучитьПравилоОбработкиДляОбъекта(КомпонентыОбмена, Объект, ПравилоОбработки);
	КонецЕсли;
	
	КомпонентыОбмена.ВыгруженныеОбъекты.Добавить(?(ОбъектСсылочногоТипа, Объект.Ссылка, Объект));
	
	// Отработка ПОД
	ИспользованиеПКО = Новый Структура;
	Для Каждого ТекущееПКО Из ПравилоОбработки.ИспользуемыеПКО Цикл
		ИспользованиеПКО.Вставить(ТекущееПКО, Истина);
	КонецЦикла;
	
	ПрерватьОбработку = Ложь;
	ВзвестиФлагОшибки = Ложь;
	
	ПриОбработкеПОД(
		КомпонентыОбмена,
		ПравилоОбработки,
		Объект,
		ИспользованиеПКО,
		ПрерватьОбработку);
	
	Если ПрерватьОбработку Тогда
		ВзвестиФлагОшибки = Истина;
	КонецЕсли;
	
	Если Не ПрерватьОбработку Тогда
		// Отработка ПКО
		НесколькоПКО = (ИспользованиеПКО.Количество() > 1);
		ЕстьКолонкаОчисткаДанных = КомпонентыОбмена.ПравилаОбработкиДанных.Колонки.Найти("ОчисткаДанных") <> Неопределено;
		
		Для Каждого ТекущееПКО Из ИспользованиеПКО Цикл
			ПравилоКонвертации = КомпонентыОбмена.ПравилаКонвертацииОбъектов.Найти(ТекущееПКО.Ключ, "ИмяПКО");
			Если ПравилоКонвертации = Неопределено Тогда
				// Допустимо указание ПКО, не предназначенного для текущей версии формата данных.
				Продолжить;
			КонецЕсли;
			
			Если Не ОбъектФорматаПроходитПоФильтруXDTO(КомпонентыОбмена, ПравилоКонвертации.ОбъектФормата) Тогда
				Продолжить;
			КонецЕсли;
			
			Если Не ТекущееПКО.Значение Тогда
				// Если правил конвертации несколько, и некоторые из них не используются -
				// необходимо выгрузить удаление объекта на случай если  ранее он был выгружен по этим правилам.
				Если НесколькоПКО
					И ОбъектСсылочногоТипа 
					И (Не ЕстьКолонкаОчисткаДанных
						Или ПравилоОбработки.ОчисткаДанных) Тогда
					ВыгрузитьУдаление(КомпонентыОбмена, Объект.Ссылка, ПравилоКонвертации);
				КонецЕсли;
				Продолжить;
			КонецЕсли;
			
			ПропуститьОбработку = Ложь;
			Попытка
				// 2. Конвертируем Данные в Структуру по правилам конвертации.
				ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
				
				ДанныеXDTO = ДанныеXDTOИзДанныхИБ(КомпонентыОбмена, Объект, ПравилоКонвертации, Неопределено);
				
				Событие = "ДанныеXDTOИзДанныхИБ." + ПравилоКонвертации.ИмяПКО;
				ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
					ВремяНачала, Событие, Объект, КомпонентыОбмена,
					ОбменДаннымиОценкаПроизводительности.ТипСобытияБиблиотека());
				
				Если ДанныеXDTO = Неопределено Тогда
					Продолжить;
				КонецЕсли;
				
				// 3. Конвертируем Структуру в ОбъектXDTO.
				ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
				
				СсылкиИзОбъекта = Новый Массив;
				ОбъектXDTO = ОбъектXDTOИзДанныхXDTO(КомпонентыОбмена, ДанныеXDTO, ПравилоКонвертации.ТипXDTO, СсылкиИзОбъекта, , ПравилоКонвертации.Расширения);
				
				Событие = "ОбъектXDTOИзДанныхXDTO." + ПравилоКонвертации.ИмяПКО;
				ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
					ВремяНачала, Событие, Объект, КомпонентыОбмена, 
					ОбменДаннымиОценкаПроизводительности.ТипСобытияБиблиотека());
				
			Исключение
				ПропуститьОбработку = Истина;
				ВзвестиФлагОшибки   = Истина;
				
				ОписаниеОшибки = ОписаниеОшибкиПКО(
					КомпонентыОбмена.НаправлениеОбмена,
					ПравилоОбработки.Имя,
					ПравилоКонвертации.ИмяПКО,
					ПредставлениеОбъектаДляПротокола(Объект, ПравилоКонвертации.ОбъектДанных),
					ИнформацияОбОшибке());
					
				ЗафиксироватьПроблемуПриОбработкеОбъекта(КомпонентыОбмена,
					Объект,
					Перечисления.ТипыПроблемОбменаДанными.ОшибкаВыполненияКодаОбработчиковПриОтправкеДанных,
					ОписаниеОшибки.ПодробноеПредставление,
					ОписаниеОшибки.КраткоеПредставление);
			КонецПопытки;
				
			Если Не ПропуститьОбработку Тогда
				ОшибкаПроверкиПоСхеме = Ложь;
				ОписаниеОшибкиПроверкиПоСхеме = Неопределено;
				
				Контекст = Новый Структура;
				Контекст.Вставить("НаправлениеОбмена",    КомпонентыОбмена.НаправлениеОбмена);
				Контекст.Вставить("ИмяПОД",               ПравилоОбработки.Имя);
				Контекст.Вставить("ИмяПКО",               ПравилоКонвертации.ИмяПКО);
				Контекст.Вставить("ПредставлениеОбъекта", ПредставлениеОбъектаДляПротокола(Объект, ПравилоКонвертации.ОбъектДанных));
				
				ПроверитьОбъектXDTOПоСхеме(ОбъектXDTO, ПравилоКонвертации.ТипXDTO, Контекст, ОшибкаПроверкиПоСхеме, ОписаниеОшибкиПроверкиПоСхеме);
				
				Если ОшибкаПроверкиПоСхеме Тогда
					ПропуститьОбработку = Истина;
					
					ЗафиксироватьПроблемуПриОбработкеОбъекта(КомпонентыОбмена,
						Объект,
						Перечисления.ТипыПроблемОбменаДанными.ОшибкаПроверкиСконвертированногоОбъекта,
						ОписаниеОшибкиПроверкиПоСхеме.ПодробноеПредставление,
						ОписаниеОшибкиПроверкиПоСхеме.КраткоеПредставление);
				КонецЕсли;
			КонецЕсли;
		
			Если ПропуститьОбработку Тогда
				ПрерватьОбработку = Истина;
				Продолжить;
			КонецЕсли;
			
			ВыгрузитьОбъектыПоСсылке(КомпонентыОбмена, СсылкиИзОбъекта);
			
			// 4. Записываем ОбъектXDTO в XML-файл.
			ФабрикаXDTO.ЗаписатьXML(КомпонентыОбмена.ФайлОбмена, ОбъектXDTO);
		КонецЦикла;
	КонецЕсли;
	
	Если ПрерватьОбработку Тогда
		КомпонентыОбмена.НеВыгруженныеОбъекты.Добавить(?(ОбъектСсылочногоТипа, Объект.Ссылка, Объект));
	КонецЕсли;
	
	Если ВзвестиФлагОшибки Тогда
		КомпонентыОбмена.ФлагОшибки = Истина;
		КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка;
	КонецЕсли;
	
КонецПроцедуры

// Выполняет преобразование структуры с данными в объект XDTO указанного типа в соответствии с правилами.
//
// Параметры:
//   КомпонентыОбмена - Структура - содержит все правила и параметры обмена.
//   Источник         - Структура - источник данных, которые необходимо преобразовать в объект XDTO.
//   ТипXDTO          - Строка - тип объекта или тип значения XDTO, к которому надо преобразовать данные.
//   СсылкиИзОбъекта  - Массив из ЛюбаяСсылка - содержит общий список выгруженных по ссылкам объектов.
//   ПроведеноЗаполнениеСвойств - Булево - параметр для определения заполненности общих составных свойств.
//   Расширения       - Структура - для служебного использования.
//
// Возвращаемое значение:
//   ОбъектXDTO - результат преобразования. 
// 
Функция ОбъектXDTOИзДанныхXDTO(КомпонентыОбмена, Знач Источник, Знач ТипXDTO, 
		СсылкиИзОбъекта = Неопределено, ПроведеноЗаполнениеСвойств = Ложь, Знач Расширения = Неопределено) Экспорт
	
	Если СсылкиИзОбъекта = Неопределено Тогда
		СсылкиИзОбъекта = Новый Массив;
	КонецЕсли;
	
	Приемник = ФабрикаXDTO.Создать(ТипXDTO);
	
	СвойстваИсточника = Новый Массив;
	Для Каждого Свойство Из ТипXDTO.Свойства Цикл
		СвойстваИсточника.Добавить(Свойство);
	КонецЦикла;
	
	ДополнитьСвойстваПакетаИзРасширений(ТипXDTO, СвойстваИсточника, КомпонентыОбмена, Расширения);
	
	Для Каждого Свойство Из СвойстваИсточника Цикл
		
		ЭтоБазоваяСхема = ЭтоБазоваяСхема(КомпонентыОбмена, Свойство.URIПространстваИмен);
		
		ЗначениеСвойства = Неопределено;
		СвойствоНайдено = Ложь;
		
		ИмяСвойстваИсточника = ТранслироватьИмя(Свойство.Имя, "en", Источник);
		
		Если ТипЗнч(Источник) = Тип("Структура") Тогда
			СвойствоНайдено = Источник.Свойство(ИмяСвойстваИсточника, ЗначениеСвойства);
		ИначеЕсли ТипЗнч(Источник) = Тип("СтрокаТаблицыЗначений")
			И Источник.Владелец().Колонки.Найти(ИмяСвойстваИсточника) <> Неопределено Тогда
			СвойствоНайдено = Истина;
			ЗначениеСвойства = Источник[ИмяСвойстваИсточника];
		КонецЕсли;
		
		ТипСвойства = Неопределено;
		ТипСвойстваПоИмениИЗначениюСвойства(ТипXDTO, СвойствоНайдено, Свойство, ЗначениеСвойства, ТипСвойства);
		
		Попытка
			Если ТипСвойства = "ОбщееСоставноеСвойство" Тогда
				
				ПроведеноЗаполнениеВложенныхСвойств = Ложь;
				Если ТипЗнч(Источник) = Тип("Структура") И СвойствоНайдено Тогда
					
					ЗначениеXDTO = ОбъектXDTOИзДанныхXDTO(КомпонентыОбмена, ЗначениеСвойства,
						Свойство.Тип, СсылкиИзОбъекта, ПроведеноЗаполнениеВложенныхСвойств, Расширения);
						
				Иначе
					
					ЗначениеXDTO = ОбъектXDTOИзДанныхXDTO(КомпонентыОбмена, Источник,
						Свойство.Тип, СсылкиИзОбъекта, ПроведеноЗаполнениеВложенныхСвойств, Расширения);
						
				КонецЕсли;
				
				Если Не ПроведеноЗаполнениеВложенныхСвойств Тогда
					Продолжить;
				КонецЕсли;
				
			Иначе
				
				Если Не СвойствоНайдено Тогда
					Продолжить;
				КонецЕсли;
				
				// Проверка на заполненность.
				Если ЗначениеСвойства = Null
					Или Не ЗначениеЗаполнено(ЗначениеСвойства) Тогда
					
					Если Свойство.ВозможноПустое Тогда
						Приемник[Свойство.Имя] = Неопределено;
					КонецЕсли;
					
					Продолжить;
					
				КонецЕсли;
				
				ЗначениеXDTO = Неопределено;
				Если ТипСвойства = КлассКлючевыеСвойстваФормата() Тогда
					
					ЗначениеXDTO = ОбъектXDTOИзДанныхXDTO(КомпонентыОбмена, ЗначениеСвойства, Свойство.Тип, СсылкиИзОбъекта, , Расширения);
					
				ИначеЕсли ТипСвойства = "ОбычноеСвойство" Тогда
					
					СвойствоТипЗначения = Свойство.Тип; // ТипЗначенияXDTO
					
					Если ЭтоСсылкаXDTO(СвойствоТипЗначения) Тогда // Конвертация ссылки
						
						ЗначениеXDTO = КонвертироватьСсылкуВXDTO(КомпонентыОбмена, ЗначениеСвойства, СвойствоТипЗначения);
						
						Если СсылкиИзОбъекта.Найти(ЗначениеСвойства) = Неопределено Тогда
							СсылкиИзОбъекта.Добавить(ЗначениеСвойства);
						КонецЕсли;
						
					ИначеЕсли СвойствоТипЗначения.Фасеты <> Неопределено
						И СвойствоТипЗначения.Фасеты.Перечисления <> Неопределено
						И СвойствоТипЗначения.Фасеты.Перечисления.Количество() > 0 Тогда // Конвертация перечисления
						ЗначениеXDTO = КонвертироватьПеречислениеВXDTO(КомпонентыОбмена, ЗначениеСвойства, СвойствоТипЗначения);
					Иначе // Конвертация обычного значения.
						ЗначениеXDTO = ФабрикаXDTO.Создать(СвойствоТипЗначения, ЗначениеСвойства);
					КонецЕсли;
					
				ИначеЕсли ТипСвойства = "AdditionalInfo" Тогда
					ЗначениеXDTO = СериализаторXDTO.ЗаписатьXDTO(ЗначениеСвойства);
					
				ИначеЕсли ТипСвойства = "Таблица" Тогда
					
					ЗначениеXDTO = ФабрикаXDTO.Создать(Свойство.Тип);
					ТипТаблицы = Свойство.Тип.Свойства[0].Тип;
					ИмяСвойстваСтроки = Свойство.Тип.Свойства[0].Имя;
					СписокXDTO = ЗначениеXDTO[ИмяСвойстваСтроки]; // СписокXDTO
					
					Для Каждого ИсточникСтрока Из ЗначениеСвойства Цикл
						
						ПриемникСтрока = ОбъектXDTOИзДанныхXDTO(КомпонентыОбмена, ИсточникСтрока, ТипТаблицы, СсылкиИзОбъекта, Ложь, Расширения);
						СписокXDTO.Добавить(ПриемникСтрока);
						
					КонецЦикла;
					
				ИначеЕсли ТипСвойства = "СвойствоСоставногоТипа" Тогда
					
					Для Каждого СвойствоСоставногоТипа Из Свойство.Тип.Свойства Цикл
						
						СоставноеЗначениеXDTO = Неопределено;
						Если ТипЗнч(ЗначениеСвойства) = Тип("Структура")
							И ЗначениеСвойства.ТипСоставногоСвойства = СвойствоСоставногоТипа.Тип Тогда
							
							// Свойство составного типа, содержащие элементы только типа КлючевыеСвойства.
							СоставноеЗначениеXDTO = ОбъектXDTOИзДанныхXDTO(КомпонентыОбмена, ЗначениеСвойства, СвойствоСоставногоТипа.Тип, СсылкиИзОбъекта, , Расширения);
						// Свойство составного типа простое, и значение простое.
						ИначеЕсли (ТипЗнч(ЗначениеСвойства) = Тип("Строка")
							И СтрНайти(СвойствоСоставногоТипа.Тип.Имя,"string")>0)
							ИЛИ (ТипЗнч(ЗначениеСвойства) = Тип("Число")
							И СтрНайти(СвойствоСоставногоТипа.Тип.Имя,"decimal")>0)
							ИЛИ (ТипЗнч(ЗначениеСвойства) = Тип("Булево")
							И СтрНайти(СвойствоСоставногоТипа.Тип.Имя,"boolean")>0)
							ИЛИ (ТипЗнч(ЗначениеСвойства) = Тип("Дата")
							И СтрНайти(СвойствоСоставногоТипа.Тип.Имя,"date")>0) Тогда
							
							СоставноеЗначениеXDTO = ЗначениеСвойства;
							
						ИначеЕсли ТипЗнч(ЗначениеСвойства) = Тип("Строка")
							И ТипЗнч(СвойствоСоставногоТипа.Тип) = Тип("ТипЗначенияXDTO")
							И СвойствоСоставногоТипа.Тип.Фасеты <> Неопределено Тогда
							Если СвойствоСоставногоТипа.Тип.Фасеты.Количество() = 0 Тогда
								СоставноеЗначениеXDTO = ЗначениеСвойства;
							Иначе
								
								Для Каждого Фасет Из СвойствоСоставногоТипа.Тип.Фасеты Цикл
									Если Фасет.Значение = ЗначениеСвойства Тогда
										СоставноеЗначениеXDTO = ЗначениеСвойства;
										Прервать;
									КонецЕсли;
								КонецЦикла;
								
							КонецЕсли;
						КонецЕсли;
						
						Если СоставноеЗначениеXDTO <> Неопределено Тогда
							Прервать;
						КонецЕсли;
						
					КонецЦикла;
					
					// Если передается значение с типом, которое не поддерживается в формате - не передаем.
					Если СоставноеЗначениеXDTO = Неопределено Тогда
						Продолжить;
					КонецЕсли;
					
					ЗначениеXDTO = ФабрикаXDTO.Создать(Свойство.Тип);
					ЗначениеXDTO.Установить(СвойствоСоставногоТипа, СоставноеЗначениеXDTO);
				КонецЕсли;
				
			КонецЕсли;
		Исключение
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Ошибка формирования объекта XDTO: Тип свойства <%1>. Имя свойства: <%2>.
				|
				|%3'"),
				ТипСвойства,
				Свойство.Имя,
				ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		КонецПопытки;
		
		Если ЭтоБазоваяСхема Или Свойство.URIПространстваИмен = Приемник.Тип().URIПространстваИмен Тогда
			Приемник[Свойство.Имя] = ЗначениеXDTO;
		Иначе
			ДополнитьОбъектXDTO(Приемник, Свойство, ЗначениеXDTO);
		КонецЕсли;

		ПроведеноЗаполнениеСвойств = Истина;
		
	КонецЦикла;
	
	Возврат Приемник;
КонецФункции

// Выполняет преобразование данных информационной базы в структуру с данными в соответствии с правилами.
//
// Параметры:
//   КомпонентыОбмена    - см. ИнициализироватьКомпонентыОбмена
//   Источник            - ЛюбаяСсылка - ссылка на выгружаемый объект информационной базы.
//   ПравилоКонвертации  - СтрокаТаблицыЗначений - строка таблицы правил конвертации объектов, 
//                         в соответствии с которой выполняется преобразование.
//   СтекВыгрузки        - Массив из ЛюбаяСсылка - ссылки на выгружаемые объекты с учетом вложенности.
//
// Возвращаемое значение:
//   Структура - результат преобразования.
//
Функция ДанныеXDTOИзДанныхИБ(КомпонентыОбмена, Источник, Знач ПравилоКонвертации, СтекВыгрузки = Неопределено) Экспорт
	
	Приемник = Новый Структура;
	
	Если СтекВыгрузки = Неопределено Тогда
		СтекВыгрузки = Новый Массив;
	КонецЕсли;
	
	Если ПравилоКонвертации.ЭтоСсылочныйТип Тогда
		
		ПозицияВСтеке = СтекВыгрузки.Найти(Источник.Ссылка);
		
		// Проверяем, выгружался ли объект по ссылке, чтобы не допустить зацикливания.
		Если ПозицияВСтеке <> Неопределено Тогда
			
			Если ПозицияВСтеке > 0 Тогда
				Возврат Неопределено;
			ИначеЕсли СтекВыгрузки.Количество() > 1 Тогда
				// Необходимо искать перебором.
				ПерваяИтерация = Истина;
				Для Каждого ЭлементСтека Из СтекВыгрузки Цикл
					Если ПерваяИтерация Тогда
						ПерваяИтерация = Ложь;
						Продолжить;
					КонецЕсли;
					Если ЭлементСтека = Источник.Ссылка Тогда
						Возврат Неопределено;
					КонецЕсли;
				КонецЦикла;
			КонецЕсли;
		КонецЕсли;
		
		СтекВыгрузки.Добавить(Источник.Ссылка);
		
		Если Не ОбщегоНазначения.СсылкаСуществует(Источник.Ссылка) Тогда
			Возврат Неопределено;
		КонецЕсли;
		
	Иначе
		СтекВыгрузки.Добавить(Источник);
	КонецЕсли;
	
	Если ПравилоКонвертации.ЭтоКонстанта Тогда
		
		ТипОбъекта = ПравилоКонвертации.ТипXDTO; // ТипОбъектаXDTO
		
		Если ТипОбъекта.Свойства.Количество() = 1 Тогда
			
			Приемник.Вставить(ТипОбъекта.Свойства[0].Имя, Источник.Значение);
			
		Иначе
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Ошибка XML-схемы. Для приемника должно быть задано одно свойство.
				|Тип источника: %1
				|Тип приемника: %2'"),
				Строка(ТипЗнч(Источник)),
				ПравилоКонвертации.ТипXDTO);
		КонецЕсли;
		
	Иначе
		
		// Выполнение ПКС, 1-й этап
		Для Каждого ПКС Из ПравилоКонвертации.Свойства Цикл
			
			Если ПравилоКонвертации.ОбъектДанных <> Неопределено
				И ПКС.СвойствоКонфигурации = ""
				И ПКС.ИспользуетсяАлгоритмКонвертации Тогда
				Продолжить;
			КонецЕсли;
			
			Если СтекВыгрузки.Количество() > 1 И Не ПКС.ОбработкаКлючевогоСвойства Тогда
				Продолжить;
			КонецЕсли;
			
			ВыгрузитьСвойство(
				КомпонентыОбмена,
				Источник,
				Приемник,
				ПКС,
				СтекВыгрузки,
				1);
		КонецЦикла;
		
		// Выполнение ПКС для ТЧ (прямая конвертация).
		Если СтекВыгрузки.Количество() = 1 Тогда
			Для Каждого ТЧИСвойства Из ПравилоКонвертации.СвойстваТабличныхЧастей Цикл
				Если НЕ (ЗначениеЗаполнено(ТЧИСвойства.ТЧКонфигурации) И ЗначениеЗаполнено(ТЧИСвойства.ТЧФормата)) Тогда
					Продолжить;
				КонецЕсли;
				// ТЧ пустая.
				Если Источник[ТЧИСвойства.ТЧКонфигурации].Количество() = 0 Тогда
					Продолжить;
				КонецЕсли;
				НоваяТЧПриемника = СоздатьТЧПриемникаПоПКС(ТЧИСвойства.Свойства);
				Для Каждого СтрокаТЧКонфигурации Из Источник[ТЧИСвойства.ТЧКонфигурации] Цикл
					СтрокаТЧПриемник = НоваяТЧПриемника.Добавить();
					Для Каждого ПКС Из ТЧИСвойства.Свойства Цикл
						Если ПКС.ИспользуетсяАлгоритмКонвертации Тогда
							Продолжить;
						КонецЕсли;
						ВыгрузитьСвойство(
							КомпонентыОбмена,
							СтрокаТЧКонфигурации,
							СтрокаТЧПриемник,
							ПКС,
							СтекВыгрузки,
							1);
					КонецЦикла;
				КонецЦикла;
				Приемник.Вставить(ТЧИСвойства.ТЧФормата, НоваяТЧПриемника);
			КонецЦикла;
		КонецЕсли;
		
		// {Обработчик: ПриОтправкеДанных} Начало
		Если ПравилоКонвертации.ЕстьОбработчикПриОтправкеДанных Тогда
			
			Если Не Приемник.Свойство(КлассКлючевыеСвойства()) Тогда
				Приемник.Вставить(КлассКлючевыеСвойства(), Новый Структура);
			КонецЕсли;
			
			ПриОтправкеДанных(Источник, Приемник, ПравилоКонвертации.ПриОтправкеДанных, КомпонентыОбмена, СтекВыгрузки);
			
			Если Приемник = Неопределено Тогда
				Возврат Неопределено;
			КонецЕсли;
			
			Если СтекВыгрузки.Количество() > 1 Тогда
				Для Каждого КлючевоеСвойство Из Приемник[КлассКлючевыеСвойства()] Цикл
					Приемник.Вставить(КлючевоеСвойство.Ключ, КлючевоеСвойство.Значение);
				КонецЦикла;
				Приемник.Удалить(КлассКлючевыеСвойства());
			КонецЕсли;
			
			// Выполнение ПКС, 2-й этап
			Для Каждого ПКС Из ПравилоКонвертации.Свойства Цикл
				Если ПКС.СвойствоФормата = "" 
					Или (СтекВыгрузки.Количество() > 1 И Не ПКС.ОбработкаКлючевогоСвойства) Тогда
					Продолжить;
				КонецЕсли;
				
				// Выполняем конвертацию, если в свойство помещена инструкция.
				ЗначениеСвойства = Неопределено;
				Если СтекВыгрузки.Количество() = 1 И ПКС.ОбработкаКлючевогоСвойства Тогда
					Приемник[КлассКлючевыеСвойства()].Свойство(ПКС.СвойствоФормата, ЗначениеСвойства);
				Иначе
					СвойствоФормата_Имя = СокрЛП(ПКС.СвойствоФормата);
					ВложенныеСвойства = СтрРазделить(СвойствоФормата_Имя,".",Ложь);
					// Указано полное имя свойства, входящего в группу общих свойств.
					Если ВложенныеСвойства.Количество() > 1 Тогда
						ПолучитьЗначениеВложенныхСвойств(Приемник, ВложенныеСвойства, ЗначениеСвойства);
					Иначе
						Приемник.Свойство(СвойствоФормата_Имя, ЗначениеСвойства);
					КонецЕсли;
				КонецЕсли;
				Если ЗначениеСвойства = Неопределено Тогда
					Продолжить;
				КонецЕсли;
				
				Если ПКС.ИспользуетсяАлгоритмКонвертации Тогда
					
					Если ТипЗнч(ЗначениеСвойства) = Тип("Структура")
						И ЗначениеСвойства.Свойство("Значение")
						И ЗначениеСвойства.Свойство("ИмяПКО")
						Или ПКС.ПравилоКонвертацииСвойства <> ""
						И ТипЗнч(ЗначениеСвойства) <> Тип("Структура") Тогда
						
						ВыгрузитьСвойство(
							КомпонентыОбмена,
							Источник,
							Приемник,
							ПКС,
							СтекВыгрузки,
							2);
							
					КонецЕсли;
						
				КонецЕсли;
			КонецЦикла;
			
			// Выполнение ПКС для ТЧ
			Если СтекВыгрузки.Количество() = 1 Тогда
				
				// Формируем структуру новых табличных частей по ПКС.
				СвойстваТЧПриемника = Новый Структура;
				Для Каждого ТЧИСвойства Из ПравилоКонвертации.СвойстваТабличныхЧастей Цикл
					
					ИмяТЧПриемника = ТЧИСвойства.ТЧФормата;
					
					Если ПустаяСтрока(ИмяТЧПриемника) Тогда
						Продолжить;
					КонецЕсли;
					
					Если Не СвойстваТЧПриемника.Свойство(ИмяТЧПриемника) Тогда
						ТаблицаПКС = Новый ТаблицаЗначений;
						ТаблицаПКС.Колонки.Добавить("СвойствоФормата", Новый ОписаниеТипов("Строка"));
						
						СвойстваТЧПриемника.Вставить(ИмяТЧПриемника, ТаблицаПКС);
					КонецЕсли;
					
					ТаблицаПКС = СвойстваТЧПриемника[ИмяТЧПриемника];
					Для Каждого ПКС Из ТЧИСвойства.Свойства Цикл
						СтрокаСвойство = ТаблицаПКС.Добавить();
						СтрокаСвойство.СвойствоФормата = ПКС.СвойствоФормата;
					КонецЦикла;
					
				КонецЦикла;
				
				Для Каждого ТЧИСвойства Из ПравилоКонвертации.СвойстваТабличныхЧастей Цикл
					
					Если Не ТЧИСвойства.ИспользуетсяАлгоритмКонвертации Тогда
						Продолжить;
					КонецЕсли;
					
					ПКСДляТЧ = ТЧИСвойства.Свойства;
					ИмяТЧПриемника = ТЧИСвойства.ТЧФормата;
					
					ТЧПриемника = Неопределено; // ТаблицаЗначений
					Если Не ЗначениеЗаполнено(ИмяТЧПриемника)
						Или Не Приемник.Свойство(ИмяТЧПриемника, ТЧПриемника) Тогда
						Продолжить;
					КонецЕсли;
					
					// Создаем новую ТЗ, в которой нет ограничений типа для колонок.
					НоваяТЧПриемника = СоздатьТЧПриемникаПоПКС(СвойстваТЧПриемника[ИмяТЧПриемника]);
					
					// Убираем лишние колонки, которые могли добавить в приемнике.
					УдаляемыеКолонки = Новый Массив;
					Для Каждого Колонка Из ТЧПриемника.Колонки Цикл
						Если НоваяТЧПриемника.Колонки.Найти(Колонка.Имя) = Неопределено Тогда
							УдаляемыеКолонки.Добавить(Колонка);
						КонецЕсли;
					КонецЦикла;
					Для Каждого Колонка Из УдаляемыеКолонки Цикл
						ТЧПриемника.Колонки.Удалить(Колонка);
					КонецЦикла;
					
					// Копируем данные в новую таблицу приемника.
					Для Каждого СтрокаТЧПриемника Из ТЧПриемника Цикл
						СтрокаНовойТЧПриемника = НоваяТЧПриемника.Добавить();
						ЗаполнитьЗначенияСвойств(СтрокаНовойТЧПриемника, СтрокаТЧПриемника);
					КонецЦикла;
					Приемник[ИмяТЧПриемника] = НоваяТЧПриемника;
					
					Для Каждого Строка Из НоваяТЧПриемника Цикл
						
						Для Каждого ПКС Из ПКСДляТЧ Цикл
							
							Если НЕ ПКС.ИспользуетсяАлгоритмКонвертации Тогда
								Продолжить;
							КонецЕсли;
							
							ВыгрузитьСвойство(
								КомпонентыОбмена,
								Источник,
								Строка,
								ПКС,
								СтекВыгрузки,
								2);
								
						КонецЦикла;
						
					КонецЦикла;
					
				КонецЦикла;
				
			КонецЕсли;
			
		КонецЕсли;
		// {Обработчик: ПриОтправкеДанных} Окончание
		
		Если СтекВыгрузки.Количество() > 1 Тогда
			Приемник.Вставить("ТипСоставногоСвойства", ПравилоКонвертации.ТипКлючевыхСвойствОбъектаXDTO);
			
			Если ЭтоБазоваяСхема(КомпонентыОбмена, ПравилоКонвертации.ПространствоИмен) И ПравилоКонвертации.Расширения.Количество() Тогда
				Для Каждого Расширение Из ПравилоКонвертации.Расширения Цикл
					Если Расширение.Значение.ТипКлючевыхСвойствОбъектаXDTO <> Неопределено Тогда
						ДанныеРасширения(Приемник, Расширение.Ключ).Вставить("ТипСоставногоСвойства",
							Расширение.Значение.ТипКлючевыхСвойствОбъектаXDTO);
					КонецЕсли;
				КонецЦикла;
			КонецЕсли;
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат Приемник;
	
КонецФункции

// Выгружает свойство объекта информационной базы в соответствии с правилами.
//
// Параметры:
//  КомпонентыОбмена   - Структура - содержит все правила и параметры обмена.
//  ДанныеИБ           - ЛюбаяСсылка - ссылка на выгружаемый объект информационной базы.
//  ПолучательСвойства - Структура - получатель данных типа Структура, в которой должно храниться значение выгруженного свойства.
//                     - СтрокаТаблицыЗначений.
//  ПКС                - СтрокаТаблицыЗначений - строка таблицы правил конвертации свойств, в соответствии с которой
//                                               выполняется преобразование.
//  СтекВыгрузки       - Массив из ЛюбаяСсылка - ссылки на выгружаемые объекты с учетом вложенности.
//  ЭтапВыгрузки       - Число - содержит информацию об этапе выгрузки:
//     1 - выгрузка до выполнения алгоритма ПриОтправкеДанных, 
//     2 - выгрузка после выполнения алгоритма ПриОтправкеДанных.
//
Процедура ВыгрузитьСвойство(КомпонентыОбмена, ДанныеИБ, ПолучательСвойства, ПКС, СтекВыгрузки, ЭтапВыгрузки = 1) Экспорт
	// Свойство формата не указано - данное ПКС используется только при загрузке.
	Если СокрЛП(ПКС.СвойствоФормата) = "" Тогда
		Возврат;
	КонецЕсли;
	
	СвойствоФормата_Имя = СокрЛП(ПКС.СвойствоФормата);
	ВложенныеСвойства = СтрРазделить(СвойствоФормата_Имя,".",Ложь);
	// Указано полное имя свойства, входящего в группу общих свойств.
	УказаноПолноеИмяСвойства = Ложь;
	Если ВложенныеСвойства.Количество() > 1 Тогда
		УказаноПолноеИмяСвойства = Истина;
		СвойствоФормата_Имя = ВложенныеСвойства[ВложенныеСвойства.Количество()-1];
	КонецЕсли;
	
	ЗначениеСвойства = Неопределено;
	Если ЭтапВыгрузки = 1 Тогда
		Если ЗначениеЗаполнено(ПКС.СвойствоКонфигурации) Тогда
			ЗначениеСвойства = ДанныеИБ[ПКС.СвойствоКонфигурации];
		ИначеЕсли ТипЗнч(ДанныеИБ) = Тип("Структура") Тогда
			// Это ПКС из ПКО с источником-структурой
			Если УказаноПолноеИмяСвойства Тогда
				ПолучитьЗначениеВложенныхСвойств(ДанныеИБ, ВложенныеСвойства, ЗначениеСвойства);
			Иначе
				ДанныеИБ.Свойство(СвойствоФормата_Имя, ЗначениеСвойства);
			КонецЕсли;
			Если ЗначениеСвойства = Неопределено Тогда
				Возврат;
			КонецЕсли;
		КонецЕсли;
	Иначе
		
		Если ТипЗнч(ПолучательСвойства) = Тип("СтрокаТаблицыЗначений") Тогда
			КолонкиТЧ = ПолучательСвойства.Владелец().Колонки;
			УровеньМаксимальный = ВложенныеСвойства.Количество() - 1;
			Если УказаноПолноеИмяСвойства Тогда
				Для Уровень = 0 По УровеньМаксимальный Цикл
					ИмяКолонки = ВложенныеСвойства[Уровень];
					Если КолонкиТЧ.Найти(ИмяКолонки) = Неопределено Тогда
						Продолжить;
					КонецЕсли;
					ЗначениеВКолонке = ПолучательСвойства[ИмяКолонки];
					Если Уровень = УровеньМаксимальный Тогда
						ЗначениеСвойства = ЗначениеВКолонке;
					ИначеЕсли ТипЗнч(ЗначениеВКолонке) = Тип("Структура") Тогда
						// Значение вложенного свойства упаковано в структуру, которая может быть многоуровневой.
						ИсточникВложенногоСвойства = ЗначениеВКолонке;
						ЗначениеВложенногоСвойства = Неопределено;
						Для УровеньПодчиненный = Уровень + 1 По УровеньМаксимальный Цикл
							ИмяВложенногоСвойства = ВложенныеСвойства[УровеньПодчиненный];
							Если НЕ ИсточникВложенногоСвойства.Свойство(ИмяВложенногоСвойства, ЗначениеВложенногоСвойства) Тогда
								Продолжить;
							КонецЕсли;
							Если УровеньПодчиненный = УровеньМаксимальный Тогда
								ЗначениеСвойства = ЗначениеВложенногоСвойства;
							ИначеЕсли ТипЗнч(ЗначениеВложенногоСвойства) = Тип("Структура") Тогда
								ИсточникВложенногоСвойства = ЗначениеВложенногоСвойства;
								ЗначениеВложенногоСвойства = Неопределено;
							Иначе
								Прервать;
							КонецЕсли;
						КонецЦикла;
					КонецЕсли;
				КонецЦикла;
			Иначе
				Если КолонкиТЧ.Найти(СвойствоФормата_Имя) = Неопределено Тогда
					Возврат;
				Иначе
					ЗначениеСвойства = ПолучательСвойства[СвойствоФормата_Имя];
				КонецЕсли;
			КонецЕсли;
		Иначе
			Если УказаноПолноеИмяСвойства Тогда
				ПолучитьЗначениеВложенныхСвойств(ДанныеИБ, ВложенныеСвойства, ЗначениеСвойства);
			Иначе
				ПолучательСвойства.Свойство(СвойствоФормата_Имя, ЗначениеСвойства);
			КонецЕсли;
			Если ЗначениеСвойства = Неопределено
				И Не (СтекВыгрузки.Количество() = 1 И ПолучательСвойства[КлассКлючевыеСвойства()].Свойство(СвойствоФормата_Имя, ЗначениеСвойства)) Тогда
				Возврат;
			КонецЕсли;
		КонецЕсли;
		
	КонецЕсли;
		
	ПравилоКонвертацииСвойства = ПКС.ПравилоКонвертацииСвойства;
	
	// Значение может быть в формате инструкции.
	Если ТипЗнч(ЗначениеСвойства) = Тип("Структура") Тогда
		Если ЗначениеСвойства.Свойство("ИмяПКО") Тогда
			ПравилоКонвертацииСвойства = ЗначениеСвойства.ИмяПКО;
		КонецЕсли;
		Если ЗначениеСвойства.Свойство("Значение") Тогда
			ЗначениеСвойства = ЗначениеСвойства.Значение;
		КонецЕсли;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ЗначениеСвойства) Тогда
	
		Если СокрЛП(ПравилоКонвертацииСвойства) <> "" Тогда
			
			ПКПД = КомпонентыОбмена.ПравилаКонвертацииПредопределенныхДанных.Найти(ПравилоКонвертацииСвойства, "ИмяПКПД");
			Если ПКПД <> Неопределено Тогда
				
				Если ТипЗнч(ЗначениеСвойства) = Тип("Строка") Тогда
					Возврат;
				КонецЕсли;
				
				ЗначениеСвойства = ПКПД.КонвертацииЗначенийПриОтправке.Получить(ЗначениеСвойства);
			
			Иначе
			
				ПравилоКонвертации = ПКОПоИмени(КомпонентыОбмена, ПравилоКонвертацииСвойства);
				
				ОтветвлениеСтекаВыгрузки = Новый Массив;
				Для Каждого Элемент Из СтекВыгрузки Цикл
					ОтветвлениеСтекаВыгрузки.Добавить(Элемент);
				КонецЦикла;
				
				ЗначениеСвойства = ДанныеXDTOИзДанныхИБ(
					КомпонентыОбмена,
					ЗначениеСвойства,
					ПравилоКонвертации,
					ОтветвлениеСтекаВыгрузки);
					
			КонецЕсли;
			
		КонецЕсли;
		
	Иначе
		ЗначениеСвойства = Неопределено;
	КонецЕсли;
	
	Если СтекВыгрузки.Количество() = 1 И ПКС.ОбработкаКлючевогоСвойства Тогда
		Если Не ПолучательСвойства.Свойство(КлассКлючевыеСвойства()) Тогда
			ПолучательСвойства.Вставить(КлассКлючевыеСвойства(), Новый Структура);
		КонецЕсли;
		ПолучательСвойства[КлассКлючевыеСвойства()].Вставить(СвойствоФормата_Имя, ЗначениеСвойства);
	Иначе
		Если ТипЗнч(ПолучательСвойства) = Тип("СтрокаТаблицыЗначений") Тогда
			Если УказаноПолноеИмяСвойства Тогда
				ПоместитьЗначениеВложенныхСвойств(ПолучательСвойства, ВложенныеСвойства, ЗначениеСвойства, Истина);
			Иначе
				ПолучательСвойства[СвойствоФормата_Имя] = ЗначениеСвойства;
			КонецЕсли;
		Иначе
			Если УказаноПолноеИмяСвойства Тогда
				ПоместитьЗначениеВложенныхСвойств(ПолучательСвойства, ВложенныеСвойства, ЗначениеСвойства, Ложь);
			Иначе
				ПолучательСвойства.Вставить(СвойствоФормата_Имя, ЗначениеСвойства);
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Открывает файл выгрузки данных, записывает заголовок файла в соответствие с форматом обмена.
//
// Параметры:
//  КомпонентыОбмена - Структура - содержит все правила и параметры обмена.
//  ИмяФайлаОбмена - Строка - имя файла обмена.
//
Процедура ОткрытьФайлВыгрузки(КомпонентыОбмена, ИмяФайлаОбмена = "") Экспорт

	ФайлОбмена = Новый ЗаписьXML;
	Если ИмяФайлаОбмена <> "" Тогда
		ФайлОбмена.ОткрытьФайл(ИмяФайлаОбмена);
	Иначе
		ФайлОбмена.УстановитьСтроку();
	КонецЕсли;
	ФайлОбмена.ЗаписатьОбъявлениеXML();
	
	ЗаписьСообщения = Неопределено;
	
	Если КомпонентыОбмена.ЭтоОбменЧерезПланОбмена Тогда

		ЗаписьСообщения = Новый Структура("НомерПринятого, НомерСообщения, Получатель");
		ЗаписьСообщения.Получатель = КомпонентыОбмена.УзелКорреспондента;
		
		Если ТранзакцияАктивна() Тогда
			ВызватьИсключение НСтр("ru = 'Блокировка на обмен данными не может быть установлена в активной транзакции.'");
		КонецЕсли;
		
		// Устанавливаем блокировку на узел получателя.
		Попытка
			ЗаблокироватьДанныеДляРедактирования(ЗаписьСообщения.Получатель);
		Исключение
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Ошибка установки блокировки на обмен данными.
				|Возможно, обмен данными выполняется другим сеансом.
				|
				|Подробности:
				|%1'"),
				ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
		КонецПопытки;
		
		ДанныеПолучателя = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(ЗаписьСообщения.Получатель, "НомерОтправленного, НомерПринятого, Код");
		
		ЗаписьСообщения.НомерСообщения = ДанныеПолучателя.НомерОтправленного + 1;
		ЗаписьСообщения.НомерПринятого = ДанныеПолучателя.НомерПринятого;
		
	КонецЕсли;
	
	ПараметрыЗаголовка = ПараметрыЗаголовкаСообщенияОбмена();
	
	ПараметрыЗаголовка.ФорматОбмена                 = КомпонентыОбмена.XMLСхема;
	ПараметрыЗаголовка.ЭтоОбменЧерезПланОбмена      = КомпонентыОбмена.ЭтоОбменЧерезПланОбмена;
	ПараметрыЗаголовка.ОбменДаннымиСВнешнейСистемой = КомпонентыОбмена.ОбменДаннымиСВнешнейСистемой;
	ПараметрыЗаголовка.ВерсияФорматаОбмена          = КомпонентыОбмена.ВерсияФорматаОбмена;
	
	Если КомпонентыОбмена.ЭтоОбменЧерезПланОбмена Тогда
		
		ПараметрыЗаголовка.УзелКорреспондента = КомпонентыОбмена.УзелКорреспондента;
		ПараметрыЗаголовка.ИдентификаторОтправителя = ОбменДаннымиСервер.ИдентификаторЭтогоУзлаДляОбмена(КомпонентыОбмена.УзелКорреспондента);
		
		Если Не КомпонентыОбмена.ТолькоНастройкиXDTO Тогда
			ПараметрыЗаголовка.НомерСообщения = ЗаписьСообщения.НомерСообщения;
			ПараметрыЗаголовка.НомерПринятого = ЗаписьСообщения.НомерПринятого;
		КонецЕсли;
		
		ПараметрыЗаголовка.ПоддерживаемыеВерсии  = КомпонентыОбмена.НастройкиXDTO.ПоддерживаемыеВерсии;
		ПараметрыЗаголовка.ПоддерживаемыеОбъекты = КомпонентыОбмена.НастройкиXDTO.ПоддерживаемыеОбъекты;
		
		Если Не КомпонентыОбмена.ОбменДаннымиСВнешнейСистемой Тогда
			ПараметрыЗаголовка.ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(КомпонентыОбмена.УзелКорреспондента);
			ПараметрыЗаголовка.ПсевдонимПредопределенногоУзла = ОбменДаннымиСервер.ПсевдонимПредопределенногоУзла(КомпонентыОбмена.УзелКорреспондента);
			
			ПараметрыЗаголовка.ИдентификаторПолучателя  = ОбменДаннымиСервер.ИдентификаторУзлаКорреспондентаДляОбмена(КомпонентыОбмена.УзелКорреспондента);
			
			ПараметрыЗаголовка.Префикс = ОбменДаннымиСервер.ПрефиксИнформационнойБазы();
		КонецЕсли;
		
		ПараметрыЗаголовка.ОбменЧерезОбработкуВыгрузкаЗагрузкаED = КомпонентыОбмена.ОбменЧерезОбработкуВыгрузкаЗагрузкаED;
		
	КонецЕсли;
	
	ЗаписатьЗаголовокСообщенияОбмена(ФайлОбмена, ПараметрыЗаголовка);
	
	Если Не КомпонентыОбмена.ТолькоНастройкиXDTO Тогда
		// Записываем элемент <Body>
		ФайлОбмена.ЗаписатьНачалоЭлемента("Body");
		
		ОбъявитьПространстваИмен(ФайлОбмена, КомпонентыОбмена);
	КонецЕсли;
	
	КомпонентыОбмена.Вставить("ФайлОбмена", ФайлОбмена);
	
КонецПроцедуры

// Определяет тип объекта формата перед конвертацией свойства
//
Процедура ТипСвойстваПоИмениИЗначениюСвойства(ТипXDTO, СвойствоНайдено, Свойство, ЗначениеСвойства, ТипСвойства)
	
	Если ТипЗнч(Свойство.Тип) = Тип("ТипЗначенияXDTO") Тогда
		
		ТипСвойства = "ОбычноеСвойство";
		
	ИначеЕсли ТипЗнч(Свойство.Тип) = Тип("ТипОбъектаXDTO") Тогда
		
		Если Свойство.Имя = "AdditionalInfo" Тогда
			
			ТипСвойства = "AdditionalInfo";
			
		ИначеЕсли ЭтоТаблицаОбъекта(Свойство) Тогда
			
			ТипСвойства = "Таблица";
			
		ИначеЕсли СтрНайти(Свойство.Тип.Имя, КлассКлючевыеСвойства()) > 0 Тогда
			
			ТипСвойства = КлассКлючевыеСвойства();
			
		ИначеЕсли СтрНайти(Свойство.Тип.Имя, КлассОбщиеСвойства()) > 0 Тогда
			
			ТипСвойства = "ОбщееСоставноеСвойство";
			
		Иначе
			
			Если СвойствоНайдено Тогда
				
				Если ТипЗнч(ЗначениеСвойства) = Тип("Структура") 
					И ЗначениеСвойства.Свойство("Значение") Тогда
					
					ТипСвойства = "ОбщееСоставноеСвойство";
					
				Иначе
					
					ТипСвойства = "СвойствоСоставногоТипа";
					
				КонецЕсли;
				
			Иначе
				
				ТипСвойства = "ОбщееСоставноеСвойство";
				
			КонецЕсли;
			
		КонецЕсли;
		
	Иначе
		
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Неизвестный тип свойства <%1>. Тип объекта: %2'"),
			Свойство.Имя,
			Строка(ТипXDTO));
			
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область ПолучениеДанных

// Возвращает объект информационной базы, соответствующий полученным данным.
// 
// Параметры:
//   КомпонентыОбмена - см. ОбменДаннымиXDTOСервер.ИнициализироватьКомпонентыОбмена
//   ДанныеXDTO       - Структура - структура, имитирующая объект XDTO.
//
//   ПравилоКонвертации - СтрокаТаблицыЗначений
//                      - Структура - параметры текущего правила конвертации:
//                        СтрокаТаблицыЗначений - строка таблицы правил конвертации объектов.
//                        Структура - описание правила конвертации объекта:
//                          * ПравилоКонвертации - СтрокаТаблицыЗначений - строка таблицы правил конвертации объектов.
//                                                 Обязательное свойство.
//                          * УдалятьСозданныеПоКлючевымСвойствам - Булево - признак необходимости удаления объектов,
//                                                                  созданных только по значениям ключевых свойств.
//                                                                  Необязательное свойство, по умолчанию Ложь.
//
//   Действие - Строка - определяет цель получения объекта ИБ:
//                       "ПолучитьСсылку" - идентификация объекта,
//                       "КонвертироватьИЗаписать" - полноценная загрузка объекта.
//
// Возвращаемое значение:
//   - Объект - объект ИБ, если передано действие "КонвертироватьИЗаписать",
//              либо если передано действие "ПолучитьСсылку" и в процессе ее получения был создан объект.
//   - ЛюбаяСсылка - ссылка на объект ИБ или пустая ссылка заданного типа, если было передано действие "ПолучитьСсылку"
//                   и в процессе ее получения объект не был создан.
//
Функция СтруктураОбъектаXDTOВДанныеИБ(КомпонентыОбмена, ДанныеXDTO, Знач ПравилоКонвертации, Действие = "КонвертироватьИЗаписать") Экспорт
	
	УдалятьСозданныеПоКлючевымСвойствам = КомпонентыОбмена.УдалятьСозданныеПоКлючевымСвойствам;
	Если ТипЗнч(ПравилоКонвертации) = Тип("Структура") Тогда
		Если ПравилоКонвертации.Свойство("УдалятьСозданныеПоКлючевымСвойствам") Тогда
			УдалятьСозданныеПоКлючевымСвойствам = ПравилоКонвертации.УдалятьСозданныеПоКлючевымСвойствам;
		КонецЕсли;
		ПравилоКонвертации = ПравилоКонвертации.ПравилоКонвертации;
	КонецЕсли;
	
	ДанныеИБ = Неопределено;
	ПолученныеДанные = ИнициализироватьПолученныеДанные(ПравилоКонвертации);
	СоставСвойств = "Все";
	ПолученныеДанныеСсылка = Неопределено;
	ДанныеXDTOСодержатСсылку = ДанныеXDTO.Свойство(КлассСсылка());
	Если ПравилоКонвертации.ЭтоСсылочныйТип Тогда
		ПолученныеДанныеСсылка = ПолученныеДанные.Ссылка;
		ВариантИдентификации = СокрЛП(ПравилоКонвертации.ВариантИдентификации);
		Если ДанныеXDTOСодержатСсылку
			И (ВариантИдентификации = "ПоУникальномуИдентификатору"
				Или ВариантИдентификации = "СначалаПоУникальномуИдентификаторуПотомПоПолямПоиска") Тогда
			
			ОригинальныйУИДСтрокой = ДанныеXDTO[КлассСсылка()].Значение;
			
			ПолученныеДанныеСсылка = СсылкаОбъектаПоУИДОбъектаXDTO(
				ОригинальныйУИДСтрокой,
				ПравилоКонвертации.ТипДанных,
				КомпонентыОбмена);
				
			ПолученныеДанные.УстановитьСсылкуНового(ПолученныеДанныеСсылка);
			
			ДанныеИБ = ПолученныеДанныеСсылка.ПолучитьОбъект();
			
			Если Действие = "ПолучитьСсылку" Тогда
				
				Если ДанныеИБ <> Неопределено Тогда
					// Задача: получение ссылки.
					// Идентификация: по УИД или УИД + поля поиска.
					// Объект с полученной ссылкой (или с таким публичным идентификатором) существует.
					ЗаписатьПриНеобходимостиПубличныйИдентификатор(
						ДанныеИБ,
						ПолученныеДанныеСсылка,
						ДанныеXDTO[КлассСсылка()].Значение,
						ПравилоКонвертации,
						КомпонентыОбмена);
						
					Возврат ДанныеИБ.Ссылка;
				ИначеЕсли ВариантИдентификации = "ПоУникальномуИдентификатору" Тогда
					// Задача: получение ссылки.
					// Идентификация: по УИД.
					// Объект с полученной ссылкой (или с таким публичным идентификатором) не найден.
					
					Возврат ПолученныеДанныеСсылка;
				КонецЕсли;
				
			КонецЕсли;
		Иначе
			ПолученныеДанныеСсылка = ПравилоКонвертации.МенеджерОбъекта.ПолучитьСсылку(Новый УникальныйИдентификатор());
			ПолученныеДанные.УстановитьСсылкуНового(ПолученныеДанныеСсылка);
		КонецЕсли;
		// Определяем, какие свойства нужно конвертировать.
		СоставСвойств = ?(Действие = "ПолучитьСсылку" И УдалятьСозданныеПоКлючевымСвойствам, "СвойстваПоиска", "Все");
	КонецЕсли;
	
	// Конвертация свойств, для которых не нужно выполнение обработчика.
	КонвертацияСвойствСтруктурыОбъектаXDTO(
		КомпонентыОбмена,
		ДанныеXDTO,
		ПолученныеДанные,
		ПравилоКонвертации,
		1,
		СоставСвойств);
		
	Если Действие = "ПолучитьСсылку" Тогда
		ДанныеXDTO = Новый Структура(КлассКлючевыеСвойства(),
			ОбщегоНазначения.СкопироватьРекурсивно(ДанныеXDTO));
	КонецЕсли;
	
	ПриКонвертацииДанныхXDTO(
		ДанныеXDTO,
		ПолученныеДанные,
		КомпонентыОбмена,
		ПравилоКонвертации.ПриКонвертацииДанныхXDTO);
		
	Если Действие = "ПолучитьСсылку" Тогда
		ДанныеXDTO = ОбщегоНазначения.СкопироватьРекурсивно(ДанныеXDTO[КлассКлючевыеСвойства()]);
	КонецЕсли;
		
	КонвертацияСвойствСтруктурыОбъектаXDTO(
		КомпонентыОбмена,
		ДанныеXDTO,
		ПолученныеДанные,
		ПравилоКонвертации,
		2,
		СоставСвойств);
		
	// В результате конвертации свойств объект мог быть записан в случае наличия циклической ссылки.
	Если ПолученныеДанныеСсылка <> Неопределено И ОбщегоНазначения.СсылкаСуществует(ПолученныеДанныеСсылка) Тогда
		ДанныеИБ = ПолученныеДанныеСсылка.ПолучитьОбъект();
	КонецЕсли;
	
	Если ДанныеИБ = Неопределено Тогда
		Если ПравилоКонвертации.ЭтоРегистр Тогда
			// Идентификация не производится, отбор набора записей выполняется в алгоритмах правил.
			ДанныеИБ = Неопределено;
		ИначеЕсли ВариантИдентификации = "ПоПолямПоиска"
			Или ВариантИдентификации = "СначалаПоУникальномуИдентификаторуПотомПоПолямПоиска" Тогда
			
			ДанныеИБ = СсылкаОбъектаПоСвойствамОбъектаXDTO(
				ПравилоКонвертации,
				ПолученныеДанные,
				ДанныеXDTOСодержатСсылку,
				КомпонентыОбмена,
				ОригинальныйУИДСтрокой);
			Если Не ЗначениеЗаполнено(ДанныеИБ) Тогда
				ДанныеИБ = Неопределено;
			КонецЕсли;
			
			// Получение (или переопределение) ссылки на найденный объект информационной базы
			// посредствам произвольного алгоритма, описанного в менеджере обмена.
			Если ПравилоКонвертации.ЕстьОбработчикАлгоритмПоиска Тогда
				АлгоритмПоиска(
					ДанныеИБ,
					ПолученныеДанные,
					КомпонентыОбмена,
					ПравилоКонвертации.АлгоритмПоиска);
			КонецЕсли;
			
			Если ДанныеИБ <> Неопределено И ПравилоКонвертации.ЭтоСсылочныйТип Тогда
				Если Действие = "ПолучитьСсылку" Тогда
					// Задача: получение ссылки.
					// Идентификация: по УИД + поля поиска.
					// Объект найден по полям поиска.
					Если ДанныеXDTOСодержатСсылку Тогда
						ЗаписатьПриНеобходимостиПубличныйИдентификатор(
							ДанныеИБ.ПолучитьОбъект(),
							ДанныеИБ,
							ДанныеXDTO[КлассСсылка()].Значение,
							ПравилоКонвертации,
							КомпонентыОбмена);
					КонецЕсли;
					
					Возврат ДанныеИБ;
				Иначе
					ДанныеИБ = ДанныеИБ.ПолучитьОбъект();
				КонецЕсли;
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЕсли;
	
	ЗаписыватьОбъектВИБ = ?(Действие = "КонвертироватьИЗаписать", Истина, Ложь);
	
	Если КомпонентыОбмена.РежимЗагрузкиДанныхВИнформационнуюБазу
		И (ВариантИдентификации = "ПоПолямПоиска"
			Или ВариантИдентификации = "СначалаПоУникальномуИдентификаторуПотомПоПолямПоиска") Тогда
		// Объекты, при идентификации которых используются поля поиска,
		// должны быть записаны в информационную базу с целью получения одной и той же ссылки на объект при каждом поиске.
		ЗаписыватьОбъектВИБ = Истина;
	КонецЕсли;
	
	Если ЗаписыватьОбъектВИБ Тогда
		
		ЭтоПолнаяЗагрузкаОбъекта = Действие = "КонвертироватьИЗаписать"
			Или ПравилоКонвертации.РазрешитьСоздаватьОбъектИзСтруктуры
			Или (Действие = "ПолучитьСсылку"
				И Не УдалятьСозданныеПоКлючевымСвойствам
				И ДанныеИБ = Неопределено);
			
		Если ЭтоПолнаяЗагрузкаОбъекта
			И ПравилоКонвертации.ЕстьОбработчикПередЗаписьюПолученныхДанных Тогда
			
			// Полноценная загрузка объекта, удаление временного объекта.
			Если ДанныеИБ <> Неопределено Тогда
				СтрокаОбъекта = КомпонентыОбмена.ТаблицаОбъектовСозданныхПоСсылкам.Найти(ДанныеИБ.Ссылка, "СсылкаНаОбъект");
				Если СтрокаОбъекта <> Неопределено Тогда
					ОбменДаннымиСервер.УстановитьОбменДаннымиЗагрузка(ДанныеИБ, Истина, Ложь, КомпонентыОбмена.УзелКорреспондента);
					УдалитьОбъект(ДанныеИБ, Истина, КомпонентыОбмена);
					ДанныеИБ = Неопределено;
					ПолученныеДанные.УстановитьСсылкуНового(СтрокаОбъекта.СсылкаНаОбъект);
				КонецЕсли;
			КонецЕсли;
			
			ПередЗаписьюПолученныхДанных(
				ПолученныеДанные,
				ДанныеИБ,
				КомпонентыОбмена,
				ПравилоКонвертации.ПередЗаписьюПолученныхДанных,
				ПравилоКонвертации.Свойства);
			
		КонецЕсли;
		
		Если ДанныеИБ = Неопределено Тогда
			ДанныеДляЗаписиВИБ = ПолученныеДанные;
		Иначе
			Если ПолученныеДанные <> Неопределено Тогда
				ЗаполнитьДанныеИБПоПолученнымДанным(ДанныеИБ, ПолученныеДанные, ПравилоКонвертации);
			КонецЕсли;
			ДанныеДляЗаписиВИБ = ДанныеИБ;
		КонецЕсли;
		
		Если ДанныеДляЗаписиВИБ = Неопределено Тогда
			Возврат Неопределено;
		КонецЕсли;
		
		Если КомпонентыОбмена.ЭтоОбменЧерезПланОбмена
			И ПравилоКонвертации.ЭтоСсылочныйТип
			И ДанныеXDTOСодержатСсылку Тогда
			
			ЗаписатьПриНеобходимостиПубличныйИдентификатор(
				ДанныеИБ,
				?(ДанныеДляЗаписиВИБ.ЭтоНовый(), ДанныеДляЗаписиВИБ.ПолучитьСсылкуНового(), ДанныеДляЗаписиВИБ.Ссылка),
				ДанныеXDTO[КлассСсылка()].Значение,
				ПравилоКонвертации,
				КомпонентыОбмена);
				
		КонецЕсли;
		
		Если ПравилоКонвертации.ЭтоСсылочныйТип И ЭтоПолнаяЗагрузкаОбъекта Тогда
			ПровестиГенерациюКодаНомераПриНеобходимости(ДанныеДляЗаписиВИБ);
		КонецЕсли;
		
		Если УдалятьСозданныеПоКлючевымСвойствам Тогда
			ДанныеДляЗаписиВИБ.ДополнительныеСвойства.Вставить("УдалятьСозданныеПоКлючевымСвойствам");
		КонецЕсли;
		
		Если КомпонентыОбмена.ЭтоОбменЧерезПланОбмена И Не ПравилоКонвертации.ЭтоРегистр Тогда
			ПолучениеЭлемента = ПолучениеЭлементаДанных.Авто;
			ОтправкаНазад = Ложь;
			СтандартныеПодсистемыСервер.ПриПолученииДанныхОтГлавного(
				ДанныеДляЗаписиВИБ, ПолучениеЭлемента, ОтправкаНазад, КомпонентыОбмена.УзелКорреспондентаОбъект);
			ДанныеДляЗаписиВИБ.ДополнительныеСвойства.Вставить("ПолучениеЭлементаДанных", ПолучениеЭлемента);
			
			Если ПолучениеЭлемента = ПолучениеЭлементаДанных.Игнорировать Тогда
				Возврат ДанныеДляЗаписиВИБ;
			КонецЕсли;
		КонецЕсли;
		
		Если ПравилоКонвертации.ЭтоСсылочныйТип И ДанныеДляЗаписиВИБ.ПометкаУдаления Тогда
			ДанныеДляЗаписиВИБ.ПометкаУдаления = Ложь;
		КонецЕсли;
		
		Если ПравилоКонвертации.ЭтоДокумент Тогда
			
			Попытка
				
				Если ПравилоКонвертации.ДокументМожетПроводиться Тогда
				
					Если ДанныеДляЗаписиВИБ.Проведен Тогда
						
						ДанныеДляЗаписиВИБ.Проведен = Ложь;
						Если Не ДанныеДляЗаписиВИБ.ЭтоНовый()
							И ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ДанныеДляЗаписиВИБ.Ссылка, "Проведен") Тогда
							// Записываем новую версию документа с отменой проведения.
							
							Результат = ОтменитьПроведениеОбъектаВИБ(ДанныеДляЗаписиВИБ, 
								КомпонентыОбмена.УзелКорреспондента, КомпонентыОбмена);
							
						Иначе
							// Записываем новую версию документа.
							ЗаписатьОбъектВИБ(КомпонентыОбмена, ДанныеДляЗаписиВИБ, ПравилоКонвертации.ТипДанных);
							Если ДанныеДляЗаписиВИБ = Неопределено Тогда
								Возврат Неопределено;
							КонецЕсли;
						КонецЕсли;
						
						СтрокаТаблицы = КомпонентыОбмена.ДокументыДляОтложенногоПроведения.Добавить();
						СтрокаТаблицы.ДокументСсылка = ДанныеДляЗаписиВИБ.Ссылка;
						СтрокаТаблицы.ДатаДокумента  = ДанныеДляЗаписиВИБ.Дата;
						
					Иначе
						Если ДанныеДляЗаписиВИБ.ЭтоНовый() Тогда
							ЗаписатьОбъектВИБ(КомпонентыОбмена, ДанныеДляЗаписиВИБ, ПравилоКонвертации.ТипДанных);
							Если ДанныеДляЗаписиВИБ = Неопределено Тогда
								Возврат Неопределено;
							КонецЕсли;
						Иначе
							
							ОтменитьПроведениеОбъектаВИБ(ДанныеДляЗаписиВИБ, 
								КомпонентыОбмена.УзелКорреспондента, КомпонентыОбмена);
						
						КонецЕсли;
					КонецЕсли;
					
				Иначе
					ЗаписатьОбъектВИБ(КомпонентыОбмена, ДанныеДляЗаписиВИБ, ПравилоКонвертации.ТипДанных);
					Если ДанныеДляЗаписиВИБ = Неопределено Тогда
						Возврат Неопределено;
					КонецЕсли;
				КонецЕсли;
				
			Исключение
				ЗаписатьВПротоколВыполнения(КомпонентыОбмена, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			КонецПопытки;
			
		Иначе
			
			ЗаписатьОбъектВИБ(КомпонентыОбмена, ДанныеДляЗаписиВИБ, ПравилоКонвертации.ТипДанных);
			Если ДанныеДляЗаписиВИБ = Неопределено Тогда
				Возврат Неопределено;
			КонецЕсли;
			Если ПравилоКонвертации.ЭтоСсылочныйТип Тогда
				КомпонентыОбмена.ОбъектыДляОтложеннойЗаписи.Вставить(
					ДанныеДляЗаписиВИБ.Ссылка, 
					ДанныеДляЗаписиВИБ.ДополнительныеСвойства);
			КонецЕсли;
		КонецЕсли;
		
		ЗапомнитьОбъектДляОтложенногоЗаполнения(ДанныеДляЗаписиВИБ, ПравилоКонвертации, КомпонентыОбмена);
		
	Иначе
		
		ДанныеДляЗаписиВИБ = ПолученныеДанные;
		
	КонецЕсли;
	
	Если ПравилоКонвертации.ЭтоСсылочныйТип Тогда
		// Объекты, создаваемые по ссылке, запоминаем в таблицу,
		// чтобы после загрузки всех данных удалить объекты, 
		// которые так и не были загружены полностью ("временные объекты").
		// При загрузке объектов "целиком" удаляем объекты из таблицы,
		// переводя их из состояния "временных" в "постоянные".
		ТаблицаОбъектовСозданныхПоСсылкам = КомпонентыОбмена.ТаблицаОбъектовСозданныхПоСсылкам;
			
		Если Действие = "ПолучитьСсылку"
			И ЗаписыватьОбъектВИБ
			И Не ПравилоКонвертации.РазрешитьСоздаватьОбъектИзСтруктуры Тогда
			
			СтрокаОбъекта = ТаблицаОбъектовСозданныхПоСсылкам.Найти(ДанныеДляЗаписиВИБ.Ссылка, "СсылкаНаОбъект");
			
			Если СтрокаОбъекта = Неопределено Тогда
				НоваяСтрока = ТаблицаОбъектовСозданныхПоСсылкам.Добавить();
				НоваяСтрока.СсылкаНаОбъект = ДанныеДляЗаписиВИБ.Ссылка;
				НоваяСтрока.УдалятьСозданныеПоКлючевымСвойствам = УдалятьСозданныеПоКлючевымСвойствам;
			Иначе
				Если Не УдалятьСозданныеПоКлючевымСвойствам Тогда
					СтрокаОбъекта.УдалятьСозданныеПоКлючевымСвойствам = Ложь;
				КонецЕсли;
			КонецЕсли;
			
		ИначеЕсли Действие = "КонвертироватьИЗаписать" Тогда
			
			СтрокаОбъекта = ТаблицаОбъектовСозданныхПоСсылкам.Найти(ДанныеДляЗаписиВИБ.Ссылка, "СсылкаНаОбъект");
			
			Если СтрокаОбъекта <> Неопределено Тогда
				ТаблицаОбъектовСозданныхПоСсылкам.Удалить(СтрокаОбъекта);
			КонецЕсли;
			
		КонецЕсли;
	КонецЕсли;
	
	Возврат ДанныеДляЗаписиВИБ;
	
КонецФункции

// Выполняет чтение файла данных при загрузке.
//
// Параметры:
//  КомпонентыОбмена - см. ИнициализироватьКомпонентыОбмена
//  ТаблицыДляЗагрузки - ТаблицаЗначений - таблица, в которую следует загрузить данные (при интерактивном сопоставлении данных).
//
Процедура ПроизвестиЧтениеДанных(КомпонентыОбмена, ТаблицыДляЗагрузки = Неопределено) Экспорт
	
	КомпонентыОбмена.ТаблицаОбъектовСозданныхПоСсылкам.Очистить();
	
	Если ТипЗнч(ТаблицыДляЗагрузки) = Тип("ТаблицаЗначений")
		И ТаблицыДляЗагрузки.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	Если КомпонентыОбмена.ЭтоОбменЧерезПланОбмена
		И КомпонентыОбмена.УзелКорреспондентаОбъект = Неопределено Тогда
		КомпонентыОбмена.УзелКорреспондентаОбъект = КомпонентыОбмена.УзелКорреспондента.ПолучитьОбъект();
	КонецЕсли;
	
	Результаты = Неопределено;
	ПрочитатьСообщениеОбмена(КомпонентыОбмена, Результаты, ТаблицыДляЗагрузки);
	
	Если Не КомпонентыОбмена.ФлагОшибки
		И КомпонентыОбмена.РежимЗагрузкиДанныхВИнформационнуюБазу Тогда
		
		ОбменДаннымиСлужебный.ОтключитьОбновлениеКлючейДоступа(Истина);
		Попытка
			ПрименитьУдалениеОбъектов(КомпонентыОбмена, Результаты.МассивОбъектовКУдалению, Результаты.МассивЗагруженныхОбъектов);
			УдалитьВременныеОбъектыСозданныеПоСсылкам(КомпонентыОбмена);
			ОтложенноеЗаполнениеОбъектов(КомпонентыОбмена);
		
			ОбменДаннымиСлужебный.ОтключитьОбновлениеКлючейДоступа(Ложь);
		Исключение
			ОбменДаннымиСлужебный.ОтключитьОбновлениеКлючейДоступа(Ложь);
			ВызватьИсключение;
		КонецПопытки;
		
		КомпонентыОбмена.ПомеченныеНаУдалениеОбъекты = ОбщегоНазначения.СкопироватьРекурсивно(Результаты.МассивОбъектовКУдалению);
		
		Если Не КомпонентыОбмена.ФлагОшибки Тогда
			Попытка
				КомпонентыОбмена.МенеджерОбмена.ПослеКонвертации(КомпонентыОбмена);
			Исключение
				
				ШаблонОписанияОшибки = НСтр("ru = 'Направление: %1.
					|Обработчик: %2.
					|
					|Ошибка выполнения обработчика.
					|%3.'");
				
				ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,
					КомпонентыОбмена.НаправлениеОбмена,
					"ПослеКонвертации",
					ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())); 
				
				ВызватьИсключение ТекстОшибки;
				
			КонецПопытки;
				
			ОбменДаннымиСлужебный.ОтключитьОбновлениеКлючейДоступа(Истина);
			Попытка
				ВыполнитьОтложенноеПроведениеДокументов(КомпонентыОбмена);
				ОбменДаннымиСервер.ВыполнитьОтложеннуюЗаписьОбъектов(
					КомпонентыОбмена.ОбъектыДляОтложеннойЗаписи, КомпонентыОбмена.УзелКорреспондента, КомпонентыОбмена);
				
				ОбменДаннымиСлужебный.ОтключитьОбновлениеКлючейДоступа(Ложь);	
			Исключение
				ОбменДаннымиСлужебный.ОтключитьОбновлениеКлючейДоступа(Ложь);	
				ВызватьИсключение;
			КонецПопытки;
				
		КонецЕсли;
	КонецЕсли;
	
	// Фиксация успешного завершения обмена.
	Если КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена = Неопределено Тогда
		КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Выполнено;
	КонецЕсли;
	
КонецПроцедуры

// Выполняет чтение файла данных при загрузке в режиме анализа (при интерактивной синхронизации данных).
//
// Параметры:
//  КомпонентыОбмена - см. ИнициализироватьКомпонентыОбмена
//  ПараметрыАнализа - Структура - параметры интерактивной загрузки данных.
//
Процедура ПроизвестиЧтениеДанныхВРежимеАнализа(КомпонентыОбмена, ПараметрыАнализа = Неопределено) Экспорт
	
	Результаты = Неопределено;
	ПрочитатьСообщениеОбмена(КомпонентыОбмена, Результаты, , Истина);
	
	ПрименитьУдалениеОбъектов(КомпонентыОбмена, Результаты.МассивОбъектовКУдалению, Результаты.МассивЗагруженныхОбъектов);
	
КонецПроцедуры

// Открывает файл загрузки данных, записывает заголовок файла в соответствие с форматом обмена.
//
// Параметры:
//  КомпонентыОбмена - Структура - содержит все правила и параметры обмена.
//  ИмяФайлаОбмена - Строка - имя файла обмена.
//
Процедура ОткрытьФайлЗагрузки(КомпонентыОбмена, ИмяФайлаОбмена) Экспорт
	
	ЭтоОбменЧерезПланОбмена = КомпонентыОбмена.ЭтоОбменЧерезПланОбмена;
	
	ЧтениеXML = Новый ЧтениеXML;
	
	КомпонентыОбмена.ФлагОшибки = Истина;
	
	ПрерватьЦикл = Ложь;
	Пока Не ПрерватьЦикл Цикл
		ПрерватьЦикл = Истина;
		
		Попытка
			ЧтениеXML.ОткрытьФайл(ИмяФайлаОбмена);
			КомпонентыОбмена.Вставить("ФайлОбмена", ЧтениеXML);
		Исключение
			СтрокаСообщенияОбОшибке = НСтр("ru = 'Ошибка при загрузке данных: %1'");
			СтрокаСообщенияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщенияОбОшибке,
				ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			ЗаписатьВПротоколВыполнения(КомпонентыОбмена, СтрокаСообщенияОбОшибке);
			Прервать;
		КонецПопытки;
		
		ЗаполнитьКешПубличныхИдентификаторов(КомпонентыОбмена, ИмяФайлаОбмена, ЧтениеXML);
		
		ЧтениеXML.Прочитать(); // Message
		Если (ЧтениеXML.ТипУзла <> ТипУзлаXML.НачалоЭлемента
			Или ЧтениеXML.ЛокальноеИмя <> "Message") Тогда
			Если СообщениеОтНеобновленнойНастройки(ЧтениеXML) Тогда
				СтрокаСообщенияОбОшибке = НСтр("ru = 'Получение данных от источника, в котором не выполнено
					|обновление настройки синхронизации данных. Необходимо:
					|1) Для вида транспорта Интернет:
					|	- выполнить повторную синхронизацию данных через некоторое время;
					|2) Для других видов транспорта:
					|	- выполнить синхронизацию данных на стороне источника,
					|	  после этого повторно выполнить синхронизацию данных в этой информационной базе.'");
				ЗаписатьВПротоколВыполнения(КомпонентыОбмена, СтрокаСообщенияОбОшибке);
			Иначе
				ЗаписатьВПротоколВыполнения(КомпонентыОбмена, 9);
			КонецЕсли;
			Прервать;
		КонецЕсли;
		
		ЧтениеXML.Прочитать(); // Header
		Если ЧтениеXML.ТипУзла <> ТипУзлаXML.НачалоЭлемента
			Или ЧтениеXML.ЛокальноеИмя <> "Header" Тогда
			ЗаписатьВПротоколВыполнения(КомпонентыОбмена, 9);
			Прервать;
		КонецЕсли;
		
		ЗаголовокСообщенияXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ФабрикаXDTO.Тип(XMLБазоваяСхема(), "Header"));
		
		СтруктураFormat = СтрРазделить(ЗаголовокСообщенияXDTO.Format, " ", Ложь);
		
		URIФормата = СтруктураFormat[0];
		
		URIРасширения = "";
		Если СтруктураFormat.Количество() > 1 Тогда
			URIРасширения = СтруктураFormat[СтруктураFormat.ВГраница()];
		КонецЕсли;
		
		Если ЭтоОбменЧерезПланОбмена Тогда
			
			Если Не ЗаголовокСообщенияXDTO.Установлено("Confirmation") Тогда
				ЗаписатьВПротоколВыполнения(КомпонентыОбмена, 9);
				Прервать;
			КонецЕсли;
			
			ПодтверждениеXDTO = ЗаголовокСообщенияXDTO.Confirmation;
			
			ИмяПланаОбмена = НайтиИмяПланаОбменаЧерезУниверсальныйФормат(КомпонентыОбмена, ПодтверждениеXDTO); 
			Если Не ЗначениеЗаполнено(ИмяПланаОбмена) Тогда
				ЗаписатьВПротоколВыполнения(КомпонентыОбмена, 177);
				Прервать;
			КонецЕсли;
			
			ФорматПланаОбмена = ОбменДаннымиСервер.ЗначениеНастройкиПланаОбмена(ИмяПланаОбмена, "ФорматОбмена");
			
			КомпонентыОбмена.ТолькоНастройкиXDTO =
				Не ОбменДаннымиСервер.НастройкаСинхронизацииЗавершена(КомпонентыОбмена.УзелКорреспондента)
					Или (URIФормата = ФорматПланаОбмена);
			
			Если ПодтверждениеXDTO.MessageNo <> Неопределено Тогда		
				КомпонентыОбмена.НомерВходящегоСообщения = ПодтверждениеXDTO.MessageNo;
			Иначе
				КомпонентыОбмена.НомерВходящегоСообщения = 0;
			КонецЕсли;
			Если ПодтверждениеXDTO.ReceivedNo <> Неопределено Тогда
				КомпонентыОбмена.НомерСообщенияПолученногоКорреспондентом = ПодтверждениеXDTO.ReceivedNo;
			Иначе
				КомпонентыОбмена.НомерСообщенияПолученногоКорреспондентом = 0;
			КонецЕсли;
			
			КодОтКого = ПодтверждениеXDTO.From;
			КодКому   = ПодтверждениеXDTO.To;
			
			Если Не КомпонентыОбмена.ТолькоНастройкиXDTO Тогда
				КомпонентыОбмена.XMLСхема = URIФормата;
				
				ВключитьПространствоИмен(КомпонентыОбмена, URIРасширения, "ext");
				
				ФорматОбмена = РазложитьФорматОбмена(КомпонентыОбмена.XMLСхема);
				
				// Проверяем базовый формат.
				Если ФорматПланаОбмена <> ФорматОбмена.БазовыйФормат Тогда
					СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Формат сообщения обмена ""%1"" не соответствует формату плана обмена ""%2"".'"),
						ФорматОбмена.БазовыйФормат,
						ФорматПланаОбмена);
					ЗаписатьВПротоколВыполнения(КомпонентыОбмена, СтрокаСообщения);
					Прервать;
				КонецЕсли;
				
				// Проверяем версию формата сообщения обмена.
				Если ВерсииФорматаОбменаМассив(КомпонентыОбмена.УзелКорреспондента).Найти(ФорматОбмена.Версия) = Неопределено Тогда
					СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Версия ""%1"" формата сообщения обмена ""%2"" не поддерживается.'"),
						ФорматОбмена.Версия, ФорматОбмена.БазовыйФормат);
					ЗаписатьВПротоколВыполнения(КомпонентыОбмена, СтрокаСообщения);
					Прервать;
				КонецЕсли;
				
				КомпонентыОбмена.ВерсияФорматаОбмена = ФорматОбмена.Версия;
				КомпонентыОбмена.МенеджерОбмена      = МенеджерОбменаВерсииФормата(КомпонентыОбмена.ВерсияФорматаОбмена,
					КомпонентыОбмена.УзелКорреспондента);
					
				Если КомпонентыОбмена.НомерВходящегоСообщения <= 0 Тогда
					КомпонентыОбмена.ИспользоватьКвитирование = Ложь;
				КонецЕсли;
					
				Если Не КомпонентыОбмена.ОбменДаннымиСВнешнейСистемой Тогда
					
					КодОтКогоНовый = "";
					Если ЗаголовокСообщенияXDTO.Установлено("NewFrom") Тогда
						КодОтКогоНовый = ЗаголовокСообщенияXDTO.NewFrom;
					КонецЕсли;
					
					ПолучательИзСообщения = ОбменДаннымиСервер.УзелПланаОбменаПоКоду(ИмяПланаОбмена, КодКому);
					Если ПолучательИзСообщения <> ПланыОбмена[ИмяПланаОбмена].ЭтотУзел() Тогда
						// Возможно, задан виртуальный код получателя.
						ПсевдонимПредопределенногоУзла = ОбменДаннымиСервер.ПсевдонимПредопределенногоУзла(КомпонентыОбмена.УзелКорреспондента);
						Если ПсевдонимПредопределенногоУзла <> КодКому Тогда
							ЗаписатьВПротоколВыполнения(КомпонентыОбмена, 178);
							Прервать;
						КонецЕсли;
					КонецЕсли;
					
					ОтправительИзСообщения = ОбменДаннымиСервер.УзелПланаОбменаПоКоду(ИмяПланаОбмена, КодОтКого);
					Если (ОтправительИзСообщения = Неопределено
							Или ОтправительИзСообщения <> КомпонентыОбмена.УзелКорреспондента)
						И ЗначениеЗаполнено(КодОтКогоНовый) Тогда
						ОтправительИзСообщения = ОбменДаннымиСервер.УзелПланаОбменаПоКоду(ИмяПланаОбмена, КодОтКогоНовый);
					КонецЕсли;
					
					Если ОтправительИзСообщения = Неопределено
						Или ОтправительИзСообщения <> КомпонентыОбмена.УзелКорреспондента Тогда
						
						СтрокаСообщения = НСтр("ru = 'Не найден узел обмена для загрузки данных. План обмена: %1, Идентификатор: %2'");
						СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, ИмяПланаОбмена, КодОтКого);
						ЗаписатьВПротоколВыполнения(КомпонентыОбмена, СтрокаСообщения);
						Прервать;
						
					КонецЕсли;
				КонецЕсли;
				
				Если КомпонентыОбмена.ИспользоватьКвитирование Тогда
					
					НомерПринятого = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(КомпонентыОбмена.УзелКорреспондента, "НомерПринятого");
					
					Если НомерПринятого >= КомпонентыОбмена.НомерВходящегоСообщения Тогда
						// Номер сообщения меньше либо равен ранее принятому.
						КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена =
							Перечисления.РезультатыВыполненияОбмена.Предупреждение_СообщениеОбменаБылоРанееПринято;
							
						ЗаписатьВПротоколВыполнения(КомпонентыОбмена, 174,,,,, Истина);
						КомпонентыОбмена.ТолькоНастройкиXDTO = Истина;
					Иначе
						// Добавляем публичные идентификаторы для ссылочных объектов, о получении которых отчитался узел-корреспондент.
						ДобавитьВыгруженныеОбъектыВРегистрПубличныеИдентификаторы(КомпонентыОбмена);
						
						// Удаляем регистрацию изменений, о получении которых отчитался узел-корреспондент.
						ПланыОбмена.УдалитьРегистрациюИзменений(КомпонентыОбмена.УзелКорреспондента, КомпонентыОбмена.НомерСообщенияПолученногоКорреспондентом);
						
						// Снимаем признак начальной выгрузки данных.
						РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.СнятьПризнакНачальнойВыгрузкиДанных(
							КомпонентыОбмена.УзелКорреспондента, КомпонентыОбмена.НомерСообщенияПолученногоКорреспондентом);
					КонецЕсли;
					
				КонецЕсли;
					
			КонецЕсли;
			
			Если КомпонентыОбмена.ОбменДаннымиСВнешнейСистемой Тогда
				КомпонентыОбмена.ИдентификаторКорреспондента = КодОтКого;
			КонецЕсли;
			
			ЗаполнитьСтруктуруНастроекXDTOКорреспондента(КомпонентыОбмена.НастройкиXDTOКорреспондента,
				ЗаголовокСообщенияXDTO, Не (URIФормата = ФорматПланаОбмена), КомпонентыОбмена.УзелКорреспондента);
				
			Если ЗаголовокСообщенияXDTO.Установлено("Prefix") Тогда
				КомпонентыОбмена.ПрефиксКорреспондента = ЗаголовокСообщенияXDTO.Prefix;
			КонецЕсли;
			
			ОбменДаннымиКонтрольЗацикливания.ЗагрузитьКонтурИзСообщения(КомпонентыОбмена, ЗаголовокСообщенияXDTO);
			
			// Проверяем поддержку кодировки по УИДам в корреспонденте.
			КомпонентыОбмена.Вставить("КорреспондентПоддерживаетИдентификаторОбменаДанными",
				ВерсияПоддерживается(КомпонентыОбмена.НастройкиXDTOКорреспондента.ПоддерживаемыеВерсии, НомерВерсииСПоддержкойИдентификатораОбменаДанными()));
				
		Иначе
				
			КомпонентыОбмена.XMLСхема = URIФормата;
			ВключитьПространствоИмен(КомпонентыОбмена, URIРасширения, "ext");
			
			ФорматОбмена = РазложитьФорматОбмена(КомпонентыОбмена.XMLСхема);
			
			КомпонентыОбмена.ВерсияФорматаОбмена = ФорматОбмена.Версия;
			КомпонентыОбмена.МенеджерОбмена      = МенеджерОбменаВерсииФормата(КомпонентыОбмена.ВерсияФорматаОбмена);
			
		КонецЕсли;
		
		Если Не КомпонентыОбмена.ТолькоНастройкиXDTO Тогда
			Если ЧтениеXML.ТипУзла <> ТипУзлаXML.НачалоЭлемента
				Или ЧтениеXML.ЛокальноеИмя <> "Body" Тогда
				ЗаписатьВПротоколВыполнения(КомпонентыОбмена, 9);
				Прервать;
			КонецЕсли;
			
			ЧтениеXML.Прочитать(); // Body
		КонецЕсли;
		
		КомпонентыОбмена.ФлагОшибки = Ложь;
		
	КонецЦикла;
	
	Если КомпонентыОбмена.ФлагОшибки Тогда
		ЧтениеXML.Закрыть();
	Иначе
		КомпонентыОбмена.Вставить("ФайлОбмена", ЧтениеXML);
	КонецЕсли;
	
КонецПроцедуры

// Выполняет преобразование объекта XDTO в структуру с данными.
//
// Параметры:
//  ОбъектXDTO - ОбъектXDTO - значение, которое необходимо преобразовать.
//  КомпонентыОбмена - см. ИнициализироватьКомпонентыОбмена
//
// Возвращаемое значение:
//  Структура - структура, имитирующая объект XDTO.
//    Ключи структуры соответствуют свойствам объекта XDTO.
//    Значения соответствуют значениям свойств объекта XDTO.
//
Функция ОбъектXDTOВСтруктуру(ОбъектXDTO, КомпонентыОбмена) Экспорт
	
	Если Не ПространствоИменАктивно(КомпонентыОбмена, ОбъектXDTO.Тип().URIПространстваИмен) Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Приемник = Новый Структура;
	
	Для Каждого Свойство Из ОбъектXDTO.Свойства() Цикл
		
		КонвертацияСвойстваXDTOВЭлементСтруктуры(ОбъектXDTO, Свойство, Приемник, КомпонентыОбмена);
		
	КонецЦикла;
	
	КлючевыеСвойстваКопия = Неопределено;
	СсылкаКопия = Неопределено;
	Если Приемник.Свойство(КлассКлючевыеСвойстваФормата(), КлючевыеСвойстваКопия)
		И ТипЗнч(КлючевыеСвойстваКопия) = Тип("Структура")
		И КлючевыеСвойстваКопия.Свойство(КлассСсылкаФормата(), СсылкаКопия)
		Тогда
		
		Приемник.Вставить(КлассСсылкаФормата(), СсылкаКопия);
		
	КонецЕсли;
	
	Приемник = ТранслироватьСтруктуру(Приемник, "en");
	
	Возврат Приемник;
КонецФункции

// Преобразует строковое представление УИД в ссылку на объект текущей информационной базы.
// Сначала выполняется поиск УИД в регистре публичных идентификаторов.
// При удачном поиске возвращается ссылка из регистра, при неудачном
// возвращается либо ссылка с исходным УИД (если она еще не сопоставлена),
// либо выполняется генерация новой ссылки со случайным УИД.
// И в том и в другом случае в регистре публичных идентификаторов создается запись.
// 
// Параметры:
//  УИДОбъектаXDTO       - Строка - уникальный идентификатор объекта XDTO, для которого необходимо 
//                                  получить ссылку соответствующего объекта информационной базы.
//
//  ТипЗначенияОбъектаИБ - Тип - тип объекта информационной базы, которому должна соответствовать
//                               получаемая ссылка.
//
//  КомпонентыОбмена     - Структура - содержит все необходимые данные, инициализированные при начале
//                                     выполнения обмена (ПКО, ПКПД, ПОД и т.д.).
//
// Возвращаемое значение:
//   ЛюбаяСсылка - ссылка на объект информационной базы.
// 
Функция СсылкаОбъектаПоУИДОбъектаXDTO(УИДОбъектаXDTO, ТипЗначенияОбъектаИБ, КомпонентыОбмена) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	// Определение ссылки на объект через публичную ссылку.
	ПубличнаяСсылка = НайтиСсылкуПоПубличномуИдентификатору(УИДОбъектаXDTO, КомпонентыОбмена, ТипЗначенияОбъектаИБ);
	Если ПубличнаяСсылка <> Неопределено Тогда
		// Найден публичный идентификатор.
		Возврат ПубличнаяСсылка;
	КонецЕсли;
	
	// Поиск ссылки по исходному УИД.
	СсылкаПоУИД = СсылкаПоУИД(ТипЗначенияОбъектаИБ, УИДОбъектаXDTO, КомпонентыОбмена);
	
	// Найдена ссылка по УИД или создана новая ссылка.
	Возврат СсылкаПоУИД;
	
КонецФункции

// Записывает объект в информационную базу.
//
// Параметры:
//  КомпонентыОбмена - Структура - содержит все необходимые данные, 
//                инициализированные при начале выполнения обмена (ПКО, ПКПД, ПОД и т.д.).
//  Объект - Произвольный - СправочникОбъект, ДокументОбъект и др записываемый объект.
//  Тип - Строка - тип объекта строкой.
//  ЗаписатьОбъект - Булево - переменная принимает значение Ложь если запись объекта не была выполнена.
//  ОтправкаНазад - Булево - служебный флаг для установки соответствующего параметра обмена данными объекта.
//  УникальныйИдентификаторСтрокой - Строка - уникальный идентификатор объекта в виде строки.
// 
Процедура ЗаписатьОбъектВИБ(КомпонентыОбмена, Объект, Тип, ЗаписатьОбъект = Ложь, Знач ОтправкаНазад = Ложь, УникальныйИдентификаторСтрокой = "") Экспорт
	
	ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
	
	Если Не РазрешенаЗаписьОбъекта(Объект, КомпонентыОбмена) Тогда
		СтрокаСообщенияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Попытка изменения неразделенных данных (%1: %2) в разделенном режиме.'"),
			Объект.Метаданные().ПолноеИмя(), Строка(Объект));

		Если КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена = Неопределено
			Или КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Выполнено Тогда
			КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.ВыполненоСПредупреждениями;
		КонецЕсли;
		
		КодОшибки = Новый Структура;
		КодОшибки.Вставить("КраткоеПредставлениеОшибки",   СтрокаСообщенияОбОшибке);
		КодОшибки.Вставить("ПодробноеПредставлениеОшибки", СтрокаСообщенияОбОшибке);
		КодОшибки.Вставить("Уровень",                      УровеньЖурналаРегистрации.Предупреждение);
		
		ЗаписатьВПротоколВыполнения(КомпонентыОбмена, КодОшибки, , Ложь);
		
		Объект = Неопределено;
		Возврат;
	КонецЕсли;
	
	Если КомпонентыОбмена.ЭтоОбменЧерезПланОбмена Тогда
		// Устанавливаем режим загрузки данных для объекта.
		ОбменДаннымиСервер.УстановитьОбменДаннымиЗагрузка(Объект,, ОтправкаНазад, КомпонентыОбмена.УзелКорреспондента);
	Иначе
		ОбменДаннымиСервер.УстановитьОбменДаннымиЗагрузка(Объект,, ОтправкаНазад);
	КонецЕсли;
	
	// Выполняем проверку на пометку удаления предопределенного элемента.
	СнятьПометкуУдаленияСПредопределенногоЭлемента(Объект, Тип, КомпонентыОбмена);
	
	НачатьТранзакцию();
	Попытка
		
		// Записываем объект в транзакцию.
		Объект.Записать();
		
		ЗафиксироватьТранзакцию();
		
	Исключение
		ОтменитьТранзакцию();
		
		ЗаписатьОбъект = Ложь;
		
		ЗП         = ЗаписьПротоколаОбмена(26, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ЗП.Объект  = Объект;
		
		Если Тип <> Неопределено Тогда
			ЗП.ТипОбъекта = Тип;
		КонецЕсли;
		
		ЗаписатьВПротоколВыполнения(КомпонентыОбмена, 26, ЗП);
		
		ВызватьИсключение КомпонентыОбмена.СтрокаСообщенияОбОшибке;
		
	КонецПопытки;
	
	Событие = "ЗаписатьОбъектВИБ." + Объект.Метаданные().ПолноеИмя();
	ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
		ВремяНачала, Событие, Объект, КомпонентыОбмена,
		ОбменДаннымиОценкаПроизводительности.ТипСобытияПрикладное());
	
КонецПроцедуры

// Выполняет отложенное проведение загруженных документов после загрузки всех данных.
//
// Параметры:
//  КомпонентыОбмена - Структура - содержит все правила и параметры обмена.
//
Процедура ВыполнитьОтложенноеПроведениеДокументов(КомпонентыОбмена) Экспорт
	
	ОбменДаннымиСервер.ВыполнитьОтложенноеПроведениеДокументов(
		КомпонентыОбмена.ДокументыДляОтложенногоПроведения,
		КомпонентыОбмена.УзелКорреспондента,
		,
		КомпонентыОбмена);
	
КонецПроцедуры

// Выполняет проведение документа при его загрузке в информационную базу.
//
// Параметры:
//  КомпонентыОбмена                         - Структура - содержит все правила и параметры обмена.
//  Объект                                   - ДокументОбъект - загруженный документ.
//  РегистрироватьПроблемыВРезультатахОбмена - Булево - необходимо регистрировать проблемы.
//
Процедура ВыполнитьПроведениеДокументаПриЗагрузке(
		КомпонентыОбмена,
		Объект,
		РегистрироватьПроблемыВРезультатахОбмена = Истина) Экспорт
	
	ОбменДаннымиСервер.ВыполнитьПроведениеДокументаПриЗагрузке(
		КомпонентыОбмена.УзелКорреспондента,
		Объект.Ссылка,
		РегистрироватьПроблемыВРезультатахОбмена);
	
КонецПроцедуры

// Отменяет проведение объекта в информационной базе.
//
// Параметры:
//  Объект      - ДокументОбъект - документ для отмены проведения.
//  Отправитель - ПланОбменаСсылка - ссылка на узел плана обмена, который является отправителем данных.
//  КомпонентыОбмена - см. ИнициализироватьКомпонентыОбмена
//
// Возвращаемое значение:
//   Булево - признак успешной отмены проведения.
//
Функция ОтменитьПроведениеОбъектаВИБ(Объект, Отправитель, КомпонентыОбмена = Неопределено) Экспорт
	
	ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
	
	РегистрыСведений.РезультатыОбменаДанными.ЗарегистрироватьУстранениеПроблемы(Объект,
		Перечисления.ТипыПроблемОбменаДанными.НепроведенныйДокумент);
		
	// Проверка на коллизии дат запрета загрузки.
	Объект.ДополнительныеСвойства.Вставить("ПропуститьПроверкуЗапретаИзменения");
	
	// Параметр "СинхронизацияДанныхЧерезУниверсальныйФорматУдалениеДвижений" используется при 
	// обработке удаления движений, например, в модуле набора записей регистра накопления.
	// Если разработчик определил такой параметр в правилах конвертации, пропускаем данный этап.
	Если НЕ Объект.ДополнительныеСвойства.Свойство("СинхронизацияДанныхЧерезУниверсальныйФорматУдалениеДвижений") Тогда
		
		Объект.ДополнительныеСвойства.Вставить("СинхронизацияДанныхЧерезУниверсальныйФорматУдалениеДвижений", Истина);
		
	КонецЕсли;
	
	ПроведениеДокументаОтменено = Ложь;
	
	НачатьТранзакцию();
	Попытка
		
		Если Объект.ДополнительныеСвойства.Свойство("ИспользоватьОтменуПроведенияДляОчисткиДвижений")
			И Объект.ДополнительныеСвойства.ИспользоватьОтменуПроведенияДляОчисткиДвижений = Истина Тогда
			
			ОбменДаннымиСервер.УстановитьОбменДаннымиЗагрузка(Объект, Ложь, Ложь, Отправитель);
			Объект.Записать(РежимЗаписиДокумента.ОтменаПроведения);
			
			ОбменДаннымиСервер.УстановитьОбменДаннымиЗагрузка(Объект, Истина, Ложь, Отправитель);
			
		Иначе
			
			// Устанавливаем режим загрузки данных для объекта.
			ОбменДаннымиСервер.УстановитьОбменДаннымиЗагрузка(Объект, Истина, Ложь, Отправитель);
			
			// Отменяем проведение документа.
			Объект.Проведен = Ложь;
			Объект.Записать();
			
			ОбменДаннымиСервер.УдалитьДвиженияУДокумента(Объект);
			
		КонецЕсли;
		
		Объект.ДополнительныеСвойства.Удалить("СинхронизацияДанныхЧерезУниверсальныйФорматУдалениеДвижений");
		
		ПроведениеДокументаОтменено = Истина;
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
	КонецПопытки;
	
	Если КомпонентыОбмена <> Неопределено Тогда
		Событие = "ОтменитьПроведениеОбъектаВИБ." + Объект.Метаданные().ПолноеИмя();
		ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
			ВремяНачала, Событие, Объект, КомпонентыОбмена,
			ОбменДаннымиОценкаПроизводительности.ТипСобытияБиблиотека());
	КонецЕсли;
	
	Возврат ПроведениеДокументаОтменено;
	
КонецФункции

// Процедура заполняет табличную часть объекта с учетом предыдущей версии табличной части (до загрузки данных).
//
// Параметры:
//  ТабличнаяЧастьОбъектаПослеОбработки - ТабличнаяЧасть - табличная часть, которая содержит измененные данные.
//  ТабличнаяЧастьОбъектаДоОбработки    - ТаблицаЗначений - таблица значений, содержимое табличной части объекта до
//                                                          загрузки данных.
//  КлючевыеПоля                        - Строка - колонки, по которым происходит поиск строк в табличной части (строка через
//                                        запятую).
//  КолонкиДляВключения                 - Строка - другие колонки (кроме ключевых), значения которых должны измениться (строка
//                                        через запятую).
//  КолонкиДляИсключения                - Строка - колонки, значения которых не должны измениться (строка через запятую).
//
Процедура ЗаполнитьТабличнуюЧастьОбъектаНачальнымиДанными(
	ТабличнаяЧастьОбъектаПослеОбработки, 
	ТабличнаяЧастьОбъектаДоОбработки,
	Знач КлючевыеПоля = "",
	КолонкиДляВключения = "", 
	КолонкиДляИсключения = "") Экспорт
	
	Если ТипЗнч(КлючевыеПоля) = Тип("Строка") Тогда
		Если КлючевыеПоля = "" Тогда
			Возврат; // Без ключевых полей нельзя получить соответствие новых и старых данных.
		Иначе
			КлючевыеПоля = СтрРазделить(КлючевыеПоля, ",");
		КонецЕсли;
	КонецЕсли;
	
	СоответствиеСтарыхИНовыхДанныхТЧ = СоответствиеСтарыхИНовыхДанныхТЧ(
		ТабличнаяЧастьОбъектаПослеОбработки, 
		ТабличнаяЧастьОбъектаДоОбработки,
		КлючевыеПоля);
	
	Для Каждого СтрокаНовойТЧ Из ТабличнаяЧастьОбъектаПослеОбработки Цикл
		СтрокаСтаройТЧ = СоответствиеСтарыхИНовыхДанныхТЧ.Получить(СтрокаНовойТЧ);
		Если СтрокаСтаройТЧ <> Неопределено Тогда
			ЗаполнитьЗначенияСвойств(СтрокаНовойТЧ, СтрокаСтаройТЧ, КолонкиДляВключения, КолонкиДляИсключения);
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

#КонецОбласти

// Возвращает таблицу поддерживаемых в обмене объектов формата для указанного плана обмена.
// Перечень формируется на основании правил обмена из модулей менеджера обмена по соответствующим версиям.
//
// Параметры:
//  ИмяПланаОбмена - Строка - имя плана обмена XDTO.
//  Режим          - Строка - вид запрашиваемой информации: "Отправка" | "Получение" | "ОтправкаПолучение".
//                            "Отправка" - будут возвращены все объекты, для которых поддерживается отправка;
//                            "Получение" - будут возвращены все объекты, для которых поддерживается получение;
//                            "ОтправкаПолучение" - будут возвращены все поддерживаемые объекты.
//                            По умолчанию "ОтправкаПолучение".
//  УзелОбмена     - ПланОбменаСсылка
//                 - Неопределено - узел плана обмена, соответствующий корреспонденту.
//
// Возвращаемое значение:
//  ТаблицаЗначений - состав поддерживаемых объектов формата в разрезе версий:
//    * Версия    - Строка - версия формата, например, "1.5".
//    * Объект    - Строка - имя объекта формата, например, "Справочник.Номенклатура".
//    * Отправка  - Булево - признак поддержки отправки данного объекта формата.
//    * Получение - Булево - признак поддержки получения данного объекта формата.
//
Функция ПоддерживаемыеОбъектыФормата(ИмяПланаОбмена, Режим = "ОтправкаПолучение", УзелОбмена = Неопределено) Экспорт
	
	ТаблицаОбъекты = Новый ТаблицаЗначений;
	ИнициализироватьТаблицуПоддерживаемыхОбъектовФормата(ТаблицаОбъекты, Режим);
	
	ВерсииФорматаОбмена = ОбменДаннымиСервер.ЗначениеНастройкиПланаОбмена(ИмяПланаОбмена, "ВерсииФорматаОбмена");
	
	РежимОтправка  = СтрНайти(Режим, "Отправка") > 0;
	РежимПолучение = СтрНайти(Режим, "Получение") > 0;
	
	Для Каждого Версия Из ВерсииФорматаОбмена Цикл
		
		РасширенияВерсии = Новый Массив;
		
		ДоступныеРасширенияФормата = ДоступныеРасширенияФормата(Версия.Ключ);
		Если ДоступныеРасширенияФормата.Количество() > 0 Тогда
			
			Для Каждого Расширение Из ДоступныеРасширенияФормата Цикл
				
				РасширенияВерсии.Добавить(Расширение.Ключ);
				
			КонецЦикла;
			
		КонецЕсли;
		
		Если РасширенияВерсии.Количество() = 0 Тогда
			РасширенияВерсии.Добавить("");
		КонецЕсли;
		
		Для Каждого СхемаРасширения Из РасширенияВерсии Цикл
			
			Если РежимОтправка Тогда
				КомпонентыОбмена = ИнициализироватьКомпонентыОбмена("Отправка");
				
				КомпонентыОбмена.ВерсияФорматаОбмена = Версия.Ключ;
				КомпонентыОбмена.МенеджерОбмена = Версия.Значение;
				
				КомпонентыОбмена.XMLСхема = ФорматОбмена(ИмяПланаОбмена, КомпонентыОбмена.ВерсияФорматаОбмена);
				ВключитьПространствоИмен(КомпонентыОбмена, СхемаРасширения, "ext");
				
				ИнициализироватьТаблицыПравилОбмена(КомпонентыОбмена);
				
				ЗаполнитьПоддерживаемыеОбъектыФорматаПоКомпонентамОбмена(ТаблицаОбъекты, КомпонентыОбмена);
			КонецЕсли;
			
			Если РежимПолучение Тогда
				КомпонентыОбмена = ИнициализироватьКомпонентыОбмена("Получение");
				
				КомпонентыОбмена.ВерсияФорматаОбмена = Версия.Ключ;
				КомпонентыОбмена.МенеджерОбмена = Версия.Значение;
				
				КомпонентыОбмена.XMLСхема = ФорматОбмена(ИмяПланаОбмена, КомпонентыОбмена.ВерсияФорматаОбмена);
				ВключитьПространствоИмен(КомпонентыОбмена, СхемаРасширения, "ext");
				
				ИнициализироватьТаблицыПравилОбмена(КомпонентыОбмена);
				
				ЗаполнитьПоддерживаемыеОбъектыФорматаПоКомпонентамОбмена(ТаблицаОбъекты, КомпонентыОбмена);
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЦикла;
	
	ИмяАлгоритма = "ПриОпределенииПоддерживаемыхОбъектовФормата";
	ЕстьАлгоритм = ОбменДаннымиСервер.ЕстьАлгоритмМенеджераПланаОбмена(ИмяАлгоритма, ИмяПланаОбмена);
	Если ЕстьАлгоритм Тогда
		
		ПланыОбмена[ИмяПланаОбмена].ПриОпределенииПоддерживаемыхОбъектовФормата(ТаблицаОбъекты, Режим, УзелОбмена);
		
	КонецЕсли;
	
	Возврат ТаблицаОбъекты;
	
КонецФункции

// Возвращает таблицу поддерживаемых в обмене объектов формата для указанного корреспондента.
//
// Параметры:
//  УзелОбмена - ПланОбменаСсылка - узел плана обмена XDTO соответствующего корреспондента.
//  Режим          - Строка - вид запрашиваемой информации: "Отправка" | "Получение" | "ОтправкаПолучение".
//                            "Отправка" - будут возвращены все объекты, для которых поддерживается отправка;
//                            "Получение" - будут возвращены все объекты, для которых поддерживается получение;
//                            "ОтправкаПолучение" - будут возвращены все поддерживаемые объекты.
//                            По умолчанию "ОтправкаПолучение".
//
// Возвращаемое значение:
//  ТаблицаЗначений - состав поддерживаемых объектов формата в разрезе версий:
//    * Версия    - Строка - версия формата, например, "1.5".
//    * Объект    - Строка - имя объекта формата, например, "Справочник.Номенклатура".
//    * Отправка  - Булево - признак поддержки корреспондентом отправки данного объекта формата.
//    * Получение - Булево - признак поддержки корреспондентом получения данного объекта формата.
//
Функция ПоддерживаемыеОбъектыФорматаКорреспондента(УзелОбмена, Режим = "ОтправкаПолучение") Экспорт
	
	ТаблицаОбъекты = Новый ТаблицаЗначений;
	ИнициализироватьТаблицуПоддерживаемыхОбъектовФормата(ТаблицаОбъекты, Режим);
	
	НастройкиКорреспондента = РегистрыСведений.НастройкиОбменаДаннымиXDTO.ЗначениеНастройкиКорреспондента(УзелОбмена, "ПоддерживаемыеОбъекты");
	
	Если Не НастройкиКорреспондента = Неопределено Тогда
		
		Для Каждого СтрокаНастройкиКорреспондента Из НастройкиКорреспондента Цикл
			
			Если (СтрНайти(Режим, "Отправка") И СтрокаНастройкиКорреспондента.Отправка)
				Или (СтрНайти(Режим, "Получение") И СтрокаНастройкиКорреспондента.Получение) Тогда
				СтрокаОбъекты = ТаблицаОбъекты.Добавить();
				ЗаполнитьЗначенияСвойств(СтрокаОбъекты, СтрокаНастройкиКорреспондента);
			КонецЕсли;
			
		КонецЦикла;
		
	Иначе
		
		Если Не ОбменДаннымиСервер.НастройкаСинхронизацииЗавершена(УзелОбмена) Тогда
			Возврат ТаблицаОбъекты;
		КонецЕсли;
		
		ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелОбмена);
		
		ТаблицаОбъектыБазы = ПоддерживаемыеОбъектыФормата(ИмяПланаОбмена,
			"ОтправкаПолучение", ?(УзелОбмена.Пустая(), Неопределено, УзелОбмена));
		
		Для Каждого СтрокаОбъектыБазы Из ТаблицаОбъектыБазы Цикл
			
			СтрокаОбъектыКорреспондента = ТаблицаОбъекты.Добавить();
			ЗаполнитьЗначенияСвойств(СтрокаОбъектыКорреспондента, СтрокаОбъектыБазы, "Версия, Объект");
			
			Если СтрНайти(Режим, "Отправка") > 0 Тогда
				СтрокаОбъектыКорреспондента.Отправка = СтрокаОбъектыБазы.Получение;
			КонецЕсли;
			Если СтрНайти(Режим, "Получение") > 0 Тогда
				СтрокаОбъектыКорреспондента.Получение = СтрокаОбъектыБазы.Отправка;
			КонецЕсли;
			
		КонецЦикла;		
	КонецЕсли;
	
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелОбмена);
	ЕстьАлгоритм = ОбменДаннымиСервер.ЕстьАлгоритмМенеджераПланаОбмена(
		"ПриОпределенииПоддерживаемыхКорреспондентомОбъектовФормата", ИмяПланаОбмена);
	Если ЕстьАлгоритм Тогда
		ПланыОбмена[ИмяПланаОбмена].ПриОпределенииПоддерживаемыхКорреспондентомОбъектовФормата(УзелОбмена, ТаблицаОбъекты, Режим);
	КонецЕсли;
	
	ТаблицаОбъекты.Индексы.Добавить("Объект");
	
	Возврат ТаблицаОбъекты;
	
КонецФункции

// Возвращает признак режима пропуска при выгрузке объектов формата, не прошедших проверку по схеме.
// Может быть использована для установки нового значения режима.
//
// Параметры:
//   УзелИнформационнойБазы - ПланОбменаСсылка - узел плана обмена, соответствующий корреспонденту.
//   НовоеЗначение - Булево
//                 - Неопределено - новое значение режима для установки.
//                                  Если Неопределено, то значение режима не изменяется.
//
// Возвращаемое значение:
//   Булево - Истина, если при отправке данных необходимо пропускать объекты формата.
//
Функция ПропускатьОбъектыСОшибкамиПроверкиПоСхеме(УзелИнформационнойБазы, НовоеЗначение = Неопределено) Экспорт
	
	Режим = Ложь;
	
	УстановитьПривилегированныйРежим(Истина);
	
	МенеджерЗаписи = РегистрыСведений.НастройкиОбменаДаннымиXDTO.СоздатьМенеджерЗаписи();
	МенеджерЗаписи.УзелИнформационнойБазы = УзелИнформационнойБазы;
	МенеджерЗаписи.Прочитать();
	
	Если НовоеЗначение = Неопределено Тогда
		Если МенеджерЗаписи.Выбран() Тогда
			Режим = МенеджерЗаписи.ПропускатьОбъектыСОшибкамиПроверкиПоСхеме;
		КонецЕсли;
	Иначе
		МенеджерЗаписи.ПропускатьОбъектыСОшибкамиПроверкиПоСхеме = НовоеЗначение;
		МенеджерЗаписи.Записать(Истина);
		
		Режим = НовоеЗначение;
	КонецЕсли;
	
	Возврат Режим;
	
КонецФункции

// Возвращает имя свойства, которое содержит ключевые свойства объекта 
//
// Возвращаемое значение:
//   Строка - "КлючевыеСвойства".
//
Функция КлассКлючевыеСвойства() Экспорт
	
	Возврат "КлючевыеСвойства";
	
КонецФункции 

// Возвращает имя свойства, которое содержит ключевые свойства объекта пакета XDTO 
//
// Возвращаемое значение:
//   Строка - "КлючевыеСвойства".
//
Функция КлассКлючевыеСвойстваФормата() Экспорт
	
	Возврат "КлючевыеСвойства"; // @Non-NLS
	
КонецФункции

#КонецОбласти

#Область СлужебныйПрограммныйИнтерфейс

#Область ИнициализацияОбмена

// Создает таблицу значений для хранения заголовка пакета с данными.
//
// Возвращаемое значение:
//  ТаблицаЗначений - набор данных заголовка пакета:
//    * ТипОбъектаСтрокой - Строка
//    * КоличествоОбъектовВИсточнике - Число
//    * ПоляПоиска - Строка
//    * ПоляТаблицы - Строка
//    * ТипИсточникаСтрокой - Строка
//    * ТипПриемникаСтрокой - Строка
//    * СинхронизироватьПоИдентификатору - Булево
//    * ЭтоУдалениеОбъекта - Булево
//    * ЭтоКлассификатор - Булево
//    * ИспользоватьПредварительныйПросмотр - Булево
//
Функция НоваяТаблицаДанныхЗаголовкаПакета() Экспорт
	
	ТаблицаДанныхЗаголовкаПакета = Новый ТаблицаЗначений;
	Колонки = ТаблицаДанныхЗаголовкаПакета.Колонки;
	
	Колонки.Добавить("ТипОбъектаСтрокой",            Новый ОписаниеТипов("Строка"));
	Колонки.Добавить("КоличествоОбъектовВИсточнике", Новый ОписаниеТипов("Число"));
	Колонки.Добавить("ПоляПоиска",                   Новый ОписаниеТипов("Строка"));
	Колонки.Добавить("ПоляТаблицы",                  Новый ОписаниеТипов("Строка"));
	
	Колонки.Добавить("ТипИсточникаСтрокой", Новый ОписаниеТипов("Строка"));
	Колонки.Добавить("ТипПриемникаСтрокой", Новый ОписаниеТипов("Строка"));
	
	Колонки.Добавить("СинхронизироватьПоИдентификатору", Новый ОписаниеТипов("Булево"));
	Колонки.Добавить("ЭтоУдалениеОбъекта", Новый ОписаниеТипов("Булево"));
	Колонки.Добавить("ЭтоКлассификатор", Новый ОписаниеТипов("Булево"));
	Колонки.Добавить("ИспользоватьПредварительныйПросмотр", Новый ОписаниеТипов("Булево"));
	
	Возврат ТаблицаДанныхЗаголовкаПакета;
	
КонецФункции

// Получает правила регистрации объектов для плана обмена.
//
// Параметры:
//  УзелПланаОбмена - ПланОбменаСсылка - ссылка на узел плана обмена
//
// Возвращаемое значение:
//  ТаблицаЗначений
//
Функция ПравилаРегистрацииОбъектов(УзелПланаОбмена) Экспорт
	
	ПравилаРегистрацииОбъектов = ОбменДаннымиСобытия.ПравилаРегистрацииОбъектовПланаОбмена(
		ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелПланаОбмена)); 
	ТаблицаПравилаРегистрацииОбъектов = ПравилаРегистрацииОбъектов.Скопировать(, "ОбъектМетаданныхИмя, ИмяРеквизитаФлага");
	ТаблицаПравилаРегистрацииОбъектов.Индексы.Добавить("ОбъектМетаданныхИмя");
	
	Возврат ТаблицаПравилаРегистрацииОбъектов;
	
КонецФункции

// Получает свойства узла плана обмена.
//
// Параметры:
//  Узел - ПланОбменаСсылка - ссылка на узел плана обмена
//
// Возвращаемое значение:
//  Структура - ключ соответствует имени свойства, а значение - значению свойства.
//
Функция СвойстваУзлаПланаОбмена(Узел) Экспорт
	
	СвойстваУзлаПланаОбмена = Новый Структура;
	
	// получаем имена реквизитов
	ИменаРеквизитов = ОбщегоНазначения.ИменаРеквизитовПоТипу(Узел, Тип("ПеречислениеСсылка.РежимыВыгрузкиОбъектовОбмена"));
	
	// Получаем значения реквизитов.
	Если Не ПустаяСтрока(ИменаРеквизитов) Тогда
		
		СвойстваУзлаПланаОбмена = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Узел, ИменаРеквизитов);
		
	КонецЕсли;
	
	Возврат СвойстваУзлаПланаОбмена;
КонецФункции

#КонецОбласти

#Область ПолучениеДанных

// Функция проверяет формат сообщения обмена: соответствует ли он формату обмена через EnterpriseData.
//
// Параметры:
//  ЧтениеXML - ЧтениеXML - сообщение обмена.
//
// Возвращаемое значение:
//  Булево - Истина когда формат соответствует, ложь - не соответствует.
//
Функция ПроверитьФорматСообщенияОбмена(ЧтениеXML) Экспорт
	
	Если (ЧтениеXML.ТипУзла <> ТипУзлаXML.НачалоЭлемента
		Или ЧтениеXML.ЛокальноеИмя <> "Message") Тогда
		Возврат Ложь;
	КонецЕсли;
		
	ЧтениеXML.Прочитать(); // Header
	Если ЧтениеXML.ТипУзла <> ТипУзлаXML.НачалоЭлемента
		Или ЧтениеXML.ЛокальноеИмя <> "Header" Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Попытка
		ЗаголовокСообщенияXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ФабрикаXDTO.Тип(XMLБазоваяСхема(), "Header"));
	Исключение
		Возврат Ложь;
	КонецПопытки;
	
	Если ЧтениеXML.ТипУзла <> ТипУзлаXML.НачалоЭлемента
		Или ЧтениеXML.ЛокальноеИмя <> "Body" Тогда
		Возврат Ложь;
	КонецЕсли;
	Если Не ЗаголовокСообщенияXDTO.Установлено("Confirmation") Тогда
		Возврат Ложь;
	КонецЕсли;
	КомпонентыОбмена = Новый Структура("ОбменДаннымиСВнешнейСистемой, УзелКорреспондента", Ложь, Неопределено);
	ПодтверждениеXDTO = ЗаголовокСообщенияXDTO.Confirmation;
	
	ИмяПланаОбмена = НайтиИмяПланаОбменаЧерезУниверсальныйФормат(КомпонентыОбмена, ПодтверждениеXDTO);
	Если Не ЗначениеЗаполнено(ИмяПланаОбмена) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Возврат Истина;
КонецФункции

Процедура ПослеОткрытияФайлаЗагрузки(КомпонентыОбмена, Отказ, ИнициализироватьТаблицыПравил = Истина) Экспорт
	
	Если КомпонентыОбмена.ФлагОшибки Тогда
		ЗавершитьВедениеПротоколаОбмена(КомпонентыОбмена);
		Если КомпонентыОбмена.Свойство("ФайлОбмена") Тогда
			КомпонентыОбмена.ФайлОбмена.Закрыть();
		КонецЕсли;
		Отказ = Истина;
		Возврат;
	КонецЕсли;
	
	Если КомпонентыОбмена.ЭтоОбменЧерезПланОбмена Тогда
		
		Если КомпонентыОбмена.ОбменДаннымиСВнешнейСистемой Тогда
			ИзмененИдентификаторУзла = Ложь;
			ИнформационноеСообщение  = "";
			
			НачатьТранзакцию();
			Попытка
				Блокировка = Новый БлокировкаДанных;
				ЭлементБлокировки = Блокировка.Добавить(ОбщегоНазначения.ИмяТаблицыПоСсылке(КомпонентыОбмена.УзелКорреспондента));
				ЭлементБлокировки.УстановитьЗначение("Ссылка", КомпонентыОбмена.УзелКорреспондента);
				Блокировка.Заблокировать();
				
				КодУзлаКорреспондента = СокрЛП(ОбщегоНазначения.ЗначениеРеквизитаОбъекта(КомпонентыОбмена.УзелКорреспондента, "Код"));
				Если ЗначениеЗаполнено(КомпонентыОбмена.ИдентификаторКорреспондента)
					И Не КодУзлаКорреспондента = КомпонентыОбмена.ИдентификаторКорреспондента Тогда
					УзелКорреспондентаОбъект = КомпонентыОбмена.УзелКорреспондента.ПолучитьОбъект();
					УзелКорреспондентаОбъект.Код = КомпонентыОбмена.ИдентификаторКорреспондента;
					УзелКорреспондентаОбъект.ОбменДанными.Загрузка = Истина;
					УзелКорреспондентаОбъект.Записать();
					
					ИзмененИдентификаторУзла = Истина;
					
					ИнформационноеСообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Изменен идентификатор узла корреспондента (%1 -> %2).'"),
						КодУзлаКорреспондента,
						КомпонентыОбмена.ИдентификаторКорреспондента);
				КонецЕсли;
			
				ЗафиксироватьТранзакцию();
			Исключение
				ОтменитьТранзакцию();
				ВызватьИсключение;
			КонецПопытки;
			
			Если ИзмененИдентификаторУзла Тогда
				ЗаписатьВПротоколВыполнения(КомпонентыОбмена, ИнформационноеСообщение, , Ложь, , , Истина);
			КонецЕсли;
			
		КонецЕсли;
		
		ОбновитьНастройкиXDTOКорреспондента(КомпонентыОбмена);
		ОбновитьПрефиксКорреспондента(КомпонентыОбмена);
		
		Если Не КомпонентыОбмена.ТолькоНастройкиXDTO
			И ИнициализироватьТаблицыПравил Тогда
			ИнициализироватьТаблицыПравилОбмена(КомпонентыОбмена);
			ЗаполнитьСтруктуруНастроекXDTO(КомпонентыОбмена);
			ЗаполнитьПоддерживаемыеОбъектыXDTO(КомпонентыОбмена);
		КонецЕсли;
	КонецЕсли;
	
	Если КомпонентыОбмена.ТолькоНастройкиXDTO Тогда
		Если КомпонентыОбмена.Свойство("ФайлОбмена") Тогда
			КомпонентыОбмена.ФайлОбмена.Закрыть();
		КонецЕсли;
		Отказ = Истина;
		Возврат;
	КонецЕсли;
	
	Если КомпонентыОбмена.ЭтоОбменЧерезПланОбмена Тогда
		ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(КомпонентыОбмена.УзелКорреспондента);
		
		Если ОбменДаннымиСервер.ЕстьАлгоритмМенеджераПланаОбмена("ОбработчикПроверкиЗначенийПоУмолчанию", ИмяПланаОбмена) Тогда
			
			СообщениеОбОшибке = "";
			
			ПараметрыОбработчика = Новый Структура;
			ПараметрыОбработчика.Вставить("Корреспондент", КомпонентыОбмена.УзелКорреспондента);
			ПараметрыОбработчика.Вставить("ПоддерживаемыеОбъектыXDTO", КомпонентыОбмена.ПоддерживаемыеОбъектыXDTO);
			
			ПланыОбмена[ИмяПланаОбмена].ОбработчикПроверкиЗначенийПоУмолчанию(Отказ, ПараметрыОбработчика, СообщениеОбОшибке);
			
			Если Отказ Тогда
				ЗаписатьВПротоколВыполнения(КомпонентыОбмена, СообщениеОбОшибке);
				ЗавершитьВедениеПротоколаОбмена(КомпонентыОбмена);
				Возврат;
			КонецЕсли;
			
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область ПроцедурыИФункцииВерсионированияФорматаОбмена
// Возвращает менеджер обмена данными, соответствующий указанной версии формата обмена.
//
// Параметры:
//  ВерсияФормата - Строка.
//  УзелИнформационнойБазы - ПланОбменаСсылка - узел плана обмена, для которого необходимо получить менеджер обмена.
//                                              Если обмен через формат осуществляется без использования плана обмена,
//                                              УзелИнформационнойБазы не передается.
//
Функция МенеджерОбменаВерсииФормата(Знач ВерсияФормата, Знач УзелИнформационнойБазы = Неопределено) Экспорт
	
	Результат = ВерсииФорматаОбмена(УзелИнформационнойБазы).Получить(ВерсияФормата);
	
	Если Результат = Неопределено Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не определен Менеджер конвертации для версии формата обмена <%1>.'"),
			ВерсияФормата);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Возвращает строку с форматом обмена.
// Формат обмена включает: 
//  Базовый формат, предусмотренный для плана обмена.
//  Версию базового формата.
//
// Параметры:
//  ИмяПланаОбмена - Строка.
//  ВерсияФормата - Строка.
//
Функция ФорматОбмена(Знач ИмяПланаОбмена, Знач ВерсияФормата) Экспорт
	
	ФорматОбмена = ОбменДаннымиСервер.ЗначениеНастройкиПланаОбмена(ИмяПланаОбмена, "ФорматОбмена");
	
	Если Не ПустаяСтрока(ВерсияФормата) Тогда
		ФорматОбмена = ФорматОбмена + "/" + ВерсияФормата;
	КонецЕсли;
	
	Возврат ФорматОбмена;
	
КонецФункции

// Возвращает строку с номером версии формата обмена, поддерживаемой получателем данных.
//
// Параметры:
//  Получатель - ссылка на узел плана обмена, в который производится выгрузка данных.
//
Функция ВерсияФорматаОбменаПриВыгрузке(Знач Получатель) Экспорт
	
	Результат = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Получатель, "ВерсияФорматаОбмена");
	Если Не ЗначениеЗаполнено(Результат) Тогда
		
		// Если версия формата обмена не задана, то используем минимальную версию.
		Результат = МинимальнаяВерсияФорматаОбмена(Получатель);
		
	КонецЕсли;
	
	Возврат СокрЛП(Результат);
КонецФункции

// Возвращает признак поддерживается ли для узла версия формата, для которой предусмотрена кодировка узлов
//  с использованием уникальных идентификаторов.
//
Функция ПоддерживаетсяВерсияСИдентификаторомОбменаДанными(Знач УзелИнформационнойБазы) Экспорт
	
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелИнформационнойБазы);
	
	Если УзелИнформационнойБазы = ПланыОбмена[ИмяПланаОбмена].ЭтотУзел()
		Или Не ЗначениеЗаполнено(УзелИнформационнойБазы) Тогда
		ПоддерживаемыеВерсии = ВерсииФорматаОбменаМассив(УзелИнформационнойБазы);
	Иначе
		ПоддерживаемыеВерсии = Новый Массив;
		ПоддерживаемыеВерсии.Добавить(ОбщегоНазначения.ЗначениеРеквизитаОбъекта(УзелИнформационнойБазы, "ВерсияФорматаОбмена"));
	КонецЕсли;
	
	Возврат ВерсияПоддерживается(ПоддерживаемыеВерсии, НомерВерсииСПоддержкойИдентификатораОбменаДанными());
	
КонецФункции

Функция МаксимальнаяОбщаяВерсияФормата(ИмяПланаОбмена, ВерсииФорматаКорреспондента) Экспорт
	
	МаксимальнаяОбщаяВерсия = "0.0";
	
	ВерсииФормата = ВерсииФорматаОбменаМассив(ПланыОбмена[ИмяПланаОбмена].ЭтотУзел());
	
	Для Каждого ВерсияКорреспондента Из ВерсииФорматаКорреспондента Цикл
		ВерсияКорреспондента = СокрЛП(ВерсияКорреспондента);
		
		Если ВерсииФормата.Найти(ВерсияКорреспондента) = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		Если СравнитьВерсии(ВерсияКорреспондента, МаксимальнаяОбщаяВерсия) >= 0 Тогда
			МаксимальнаяОбщаяВерсия = ВерсияКорреспондента;
		КонецЕсли;
	КонецЦикла;
	
	Возврат МаксимальнаяОбщаяВерсия;
	
КонецФункции

#КонецОбласти

#Область Прочее

// Процедура добавляет объект информационной базы в фильтр разрешенных объектов.
// Параметры:
//  Данные     - ссылка на объект ИБ, который необходимо добавить в фильтр разрешенных объектов.
//  Получатель - ПланОбменаСсылка - ссылка на план обмена, для которого выполняется проверка объекта.
//
Процедура ДобавитьОбъектВФильтрРазрешенныхОбъектов(Данные, Получатель) Экспорт
	
	РегистрыСведений.ДанныеОбъектовДляРегистрацииВОбменах.ДобавитьОбъектВФильтрРазрешенныхОбъектов(Данные, Получатель);
	
КонецПроцедуры

// Функция возвращает массив узлов, в которые объект ранее выгружался.
//
// Параметры:
//  Ссылка            - ссылка на объект ИБ, для которого необходимо получить массив узлов.
//  ИмяПланаОбмена    - Строка - имя плана обмена, как объекта метаданных, по которому определяются узлы.
//  ИмяРеквизитаФлага - Строка - имя реквизита плана обмена, по которому устанавливается фильтр на выборку узлов.
// Возвращаемое значение:
//  МассивУзлов - массив узлов плана обмена, для которых установлен признак «Выгружать при необходимости», изначально
//                пуст.
//
Функция МассивУзловДляРегистрацииВыгружатьПриНеобходимости(Ссылка, ИмяПланаОбмена, ИмяРеквизитаФлага) Экспорт
	
	ШаблонТекста = "ПланОбмена.%1";
	ИмяПланаОбменаСтрокой = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонТекста, ИмяПланаОбмена);
	
	ШаблонТекстаПоле = "ШапкаПланаОбмена.%1";
	ИмяРеквизитаФлагаСтрокой = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонТекстаПоле, ИмяРеквизитаФлага);

	ТекстЗапроса = "ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	ШапкаПланаОбмена.Ссылка КАК Узел
	|ИЗ
	|	&ИмяПланаОбмена КАК ШапкаПланаОбмена
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДанныеОбъектовДляРегистрацииВОбменах КАК ДанныеОбъектовДляРегистрацииВОбменах
	|		ПО ШапкаПланаОбмена.Ссылка = ДанныеОбъектовДляРегистрацииВОбменах.УзелИнформационнойБазы
	|		И ДанныеОбъектовДляРегистрацииВОбменах.Ссылка = &Объект
	|ГДЕ
	|	НЕ ШапкаПланаОбмена.ЭтотУзел
	|	И &ИмяРеквизитаФлага = ЗНАЧЕНИЕ(Перечисление.РежимыВыгрузкиОбъектовОбмена.ВыгружатьПриНеобходимости)
	|	И НЕ ШапкаПланаОбмена.ПометкаУдаления
	|	И ДанныеОбъектовДляРегистрацииВОбменах.Ссылка = &Объект
	|	И НЕ &ПометкаУдаления";
	
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяПланаОбмена", ИмяПланаОбменаСтрокой); //@Query-part-1
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяРеквизитаФлага", ИмяРеквизитаФлагаСтрокой);
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса;
	Запрос.УстановитьПараметр("Объект",   Ссылка);
	Запрос.УстановитьПараметр("ПометкаУдаления", Ссылка.ПометкаУдаления);
	
	МассивУзлов = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Узел");
	
	Возврат МассивУзлов;
	
КонецФункции

// Выполняет запись сообщения в журнал регистрации.
//
// Параметры:
//  Комментарий      - Строка - комментарий для записи в журнал регистрации.
//  Уровень          - уровень сообщения журнала регистрации (по умолчанию Ошибка).
//  КомпонентыОбмена - Структура - содержит все правила и параметры обмена.
//
Процедура ЗаписьЖурналаРегистрацииОбменДанными(Комментарий, КомпонентыОбмена, Уровень = Неопределено, СсылкаНаОбъект = Неопределено) Экспорт
	
	УзелКорреспондента = КомпонентыОбмена.УзелКорреспондента;
	КлючСообщенияЖурналаРегистрации = КомпонентыОбмена.КлючСообщенияЖурналаРегистрации;
	
	Если Уровень = Неопределено Тогда
		Уровень = УровеньЖурналаРегистрации.Ошибка;
	КонецЕсли;
	
	ОбъектМетаданных = Неопределено;
	
	Если     УзелКорреспондента <> Неопределено
		И Не УзелКорреспондента.Пустая() Тогда
		
		ОбъектМетаданных = УзелКорреспондента.Метаданные();
		
	КонецЕсли;
	
	ЗаписьЖурналаРегистрации(КлючСообщенияЖурналаРегистрации, Уровень, ОбъектМетаданных, СсылкаНаОбъект, Комментарий);
	
КонецПроцедуры

// Параметры:
//   КомпонентыОбмена - см. ОбменДаннымиXDTOСервер.ИнициализироватьКомпонентыОбмена
// 
Процедура ЗаполнитьПоддерживаемыеОбъектыXDTO(КомпонентыОбмена) Экспорт
	
	Если Не КомпонентыОбмена.ЭтоОбменЧерезПланОбмена
		Или Не ЗначениеЗаполнено(КомпонентыОбмена.УзелКорреспондента) Тогда
		Возврат;
	КонецЕсли;
	
	Если КомпонентыОбмена.НаправлениеОбмена = "Отправка" Тогда
		
		// При отправке поддерживаются объекты:
		// - отправка которых доступна из этой базы
		// - получение которых доступно в базе-корреспонденте.
		
		ТаблицаОбъектыБазыКорреспондента = ПоддерживаемыеОбъектыФорматаКорреспондента(КомпонентыОбмена.УзелКорреспондента, "Получение");
		
	ИначеЕсли КомпонентыОбмена.НаправлениеОбмена = "Получение" Тогда
		
		// При получении поддерживаются объекты:
		// - получение которых доступно в этой базе
		// - отправка которых доступна в базе-корреспонденте.
		
		ТаблицаОбъектыБазыКорреспондента = ПоддерживаемыеОбъектыФорматаКорреспондента(КомпонентыОбмена.УзелКорреспондента, "Отправка");
		
	Иначе
		
		Возврат;
		
	КонецЕсли;
	
	ОтборПоВерсииИНаправлению = Новый Структура("Версия", КомпонентыОбмена.ВерсияФорматаОбмена);
	ОтборПоВерсииИНаправлению.Вставить(КомпонентыОбмена.НаправлениеОбмена, Истина);
	
	ТаблицаОбъектыБазыПоВерсии = КомпонентыОбмена.НастройкиXDTO.ПоддерживаемыеОбъекты.Скопировать(ОтборПоВерсииИНаправлению);
	
	ОтборПоВерсии = Новый Структура("Версия", КомпонентыОбмена.ВерсияФорматаОбмена);
	
	ТаблицаОбъектыБазыКорреспондентаПоВерсии = ТаблицаОбъектыБазыКорреспондента.Скопировать(ОтборПоВерсии);
	
	Для Каждого СтрокаОбъектыБазыПоВерсии Из ТаблицаОбъектыБазыПоВерсии Цикл
		Если ТаблицаОбъектыБазыКорреспондентаПоВерсии.Найти(СтрокаОбъектыБазыПоВерсии.Объект, "Объект") = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		КомпонентыОбмена.ПоддерживаемыеОбъектыXDTO.Добавить(СтрокаОбъектыБазыПоВерсии.Объект);
	КонецЦикла;
	
КонецПроцедуры

// Возвращаемое значение:
//   ТаблицаЗначений - таблица правил обработки (ПОД):
//     * Имя - Строка
//     * ОбъектВыборкиФормат - Строка
//     * ТипСсылкиXDTO - ТипЗначенияXDTO
//                     - ТипОбъектаXDTO
//     * ОбъектВыборкиМетаданные - ОбъектМетаданных
//     * ВыборкаДанных - Строка
//     * ИмяТаблицыДляВыборки - Строка
//     * ПриОбработке - Строка
//     * ИспользуемыеПКО - Массив из Строка
// 
Функция ТаблицаПравилОбработкиДанных(КомпонентыОбмена) Экспорт
	
	XMLСхема = КомпонентыОбмена.XMLСхема;
	ВерсияФорматаМенеджераОбмена = КомпонентыОбмена.ВерсияФорматаМенеджераОбмена;
	
	// Инициализация таблицы правил обработки данных.
	ПравилаОбработкиДанных = Новый ТаблицаЗначений;
	ПравилаОбработкиДанных.Колонки.Добавить("Имя");
	ПравилаОбработкиДанных.Колонки.Добавить("ОбъектВыборкиФормат");
	ПравилаОбработкиДанных.Колонки.Добавить("ТипСсылкиXDTO");
	ПравилаОбработкиДанных.Колонки.Добавить("ОбъектВыборкиМетаданные");
	ПравилаОбработкиДанных.Колонки.Добавить("ВыборкаДанных");
	ПравилаОбработкиДанных.Колонки.Добавить("ИмяТаблицыДляВыборки");
	ПравилаОбработкиДанных.Колонки.Добавить("ПриОбработке",    Новый ОписаниеТипов("Строка"));
	
	// ИспользуемыеПКО - массив, содержащий в себе имена ПКО, в которые может быть направлен объект из данного ПОД.
	ПравилаОбработкиДанных.Колонки.Добавить("ИспользуемыеПКО",    Новый ОписаниеТипов("Массив"));
	
	КомпонентыОбмена.МенеджерОбмена.ЗаполнитьПравилаОбработкиДанных(КомпонентыОбмена.НаправлениеОбмена, ПравилаОбработкиДанных);
	
	ЕстьРасширения = Ложь;
	Если ТипЗнч(КомпонентыОбмена.РасширенияФормата) = Тип("Соответствие") Тогда
		
		ЕстьРасширения = (КомпонентыОбмена.РасширенияФормата.Количество() > 0);
		
	КонецЕсли;
	
	КоличествоСтрок = ПравилаОбработкиДанных.Количество();
	Для НомерИтерации = 1 По КоличествоСтрок Цикл
		
		ИндексСтроки = КоличествоСтрок - НомерИтерации;
		ПОД = ПравилаОбработкиДанных.Получить(ИндексСтроки);
		
		Если КомпонентыОбмена.НаправлениеОбмена = "Получение" Тогда
			
			ТипXDTO = ФабрикаXDTO.Тип(XMLСхема, ПОД.ОбъектВыборкиФормат);
			Если ТипXDTO = Неопределено И ЕстьРасширения Тогда
				
				ТипXDTOПравилаОбработкиИзРасширенийПакетаXDTO(КомпонентыОбмена, ПОД, ТипXDTO);
				
			КонецЕсли;
			
			Если ТипXDTO = Неопределено Тогда
				
				ПравилаОбработкиДанных.Удалить(ПОД);
				Продолжить;
				
			КонецЕсли;
			
			КлючевыеСвойства = ТипXDTO.Свойства.Получить(КлассКлючевыеСвойстваФормата());
			Если КлючевыеСвойства <> Неопределено Тогда
				
				ТипКлючевыхСвойствОбъектаXDTO = КлючевыеСвойства.Тип;
				СвойствоСсылкаXDTO = ТипКлючевыхСвойствОбъектаXDTO.Свойства.Получить(КлассСсылка());
				Если СвойствоСсылкаXDTO <> Неопределено Тогда
					ПОД.ТипСсылкиXDTO = СвойствоСсылкаXDTO.Тип;
				КонецЕсли;
				
			КонецЕсли;
			
		ИначеЕсли ПОД.ОбъектВыборкиМетаданные <> Неопределено Тогда
			ПОД.ИмяТаблицыДляВыборки = ПОД.ОбъектВыборкиМетаданные.ПолноеИмя();
		КонецЕсли;
		
	КонецЦикла;
	
	Если КомпонентыОбмена.НаправлениеОбмена = "Отправка" Тогда
		ПравилаОбработкиДанных.Индексы.Добавить("Имя");
		ПравилаОбработкиДанных.Индексы.Добавить("ОбъектВыборкиМетаданные");
	Иначе
		ПравилаОбработкиДанных.Индексы.Добавить("ОбъектВыборкиФормат");
		ПравилаОбработкиДанных.Индексы.Добавить("ТипСсылкиXDTO");
	КонецЕсли;
	
	Возврат ПравилаОбработкиДанных;
КонецФункции

#КонецОбласти

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

#Область ИнициализацияОбмена

// Параметры:
//   * ВерсияФорматаМенеджераОбмена - Строка
// 
// Возвращаемое значение:
//   ТаблицаЗначений - таблица правил конвертации:
//     * ИмяПКО - Строка
//     * ОбъектДанных - Произвольный
//     * ОбъектФормата - Строка
//     * ТипПолученныхДанныхСтрокой - Строка
//     * ИмяТаблицыПолученныхДанных - Строка
//     * ПредставлениеТипаПолученныхДанных - Строка
//     * Свойства - ТаблицаЗначений
//     * ПоляПоиска - Массив из Строка
//     * ПоляПредставленияОбъекта - Строка
//     * РеквизитыШапкиПолученныхДанных - Массив из Строка
//     * ПриОтправкеДанных - Строка
//     * ПриКонвертацииДанныхXDTO - Строка
//     * ПередЗаписьюПолученныхДанных - Строка
//     * ПослеЗагрузкиВсехДанных - Строка
//     * ПравилоДляГруппыСправочника - Булево
//     * ВариантИдентификации - Строка
//     * РазрешитьСоздаватьОбъектИзСтруктуры - Произвольный
//     * СвойстваТабличныхЧастейОбработанные - ТаблицаЗначений
//     * СвойстваТабличныхЧастей - Структура
//                               -  ТаблицаЗначений
// 
Функция КоллекцияПравилКонвертации(ВерсияФорматаМенеджераОбмена)
	
	// Инициализация таблицы правил конвертации.
	ПравилаКонвертации = Новый ТаблицаЗначений;
	ПравилаКонвертации.Колонки.Добавить("ИмяПКО", Новый ОписаниеТипов("Строка"));
	ПравилаКонвертации.Колонки.Добавить("ОбъектДанных");
	ПравилаКонвертации.Колонки.Добавить("ОбъектФормата",                         Новый ОписаниеТипов("Строка"));
	ПравилаКонвертации.Колонки.Добавить("ТипПолученныхДанныхСтрокой",            Новый ОписаниеТипов("Строка",,Новый КвалификаторыСтроки(300)));
	ПравилаКонвертации.Колонки.Добавить("ИмяТаблицыПолученныхДанных",            Новый ОписаниеТипов("Строка",,Новый КвалификаторыСтроки(300)));
	ПравилаКонвертации.Колонки.Добавить("ПредставлениеТипаПолученныхДанных",     Новый ОписаниеТипов("Строка",,Новый КвалификаторыСтроки(300)));
	ПравилаКонвертации.Колонки.Добавить("Свойства",                              Новый ОписаниеТипов("ТаблицаЗначений"));
	ПравилаКонвертации.Колонки.Добавить("ПоляПоиска",                            Новый ОписаниеТипов("Массив"));
	ПравилаКонвертации.Колонки.Добавить("ПоляПредставленияОбъекта",              Новый ОписаниеТипов("Строка",,Новый КвалификаторыСтроки(300)));
	ПравилаКонвертации.Колонки.Добавить("РеквизитыШапкиПолученныхДанных",        Новый ОписаниеТипов("Массив"));
	ПравилаКонвертации.Колонки.Добавить("ПриОтправкеДанных",                     Новый ОписаниеТипов("Строка"));
	ПравилаКонвертации.Колонки.Добавить("ПриКонвертацииДанныхXDTO",              Новый ОписаниеТипов("Строка"));
	ПравилаКонвертации.Колонки.Добавить("ПередЗаписьюПолученныхДанных",          Новый ОписаниеТипов("Строка"));
	ПравилаКонвертации.Колонки.Добавить("ПослеЗагрузкиВсехДанных",               Новый ОписаниеТипов("Строка"));
	ПравилаКонвертации.Колонки.Добавить("ПравилоДляГруппыСправочника",           Новый ОписаниеТипов("Булево"));
	ПравилаКонвертации.Колонки.Добавить("ВариантИдентификации",                  Новый ОписаниеТипов("Строка",,Новый КвалификаторыСтроки(60)));
	ПравилаКонвертации.Колонки.Добавить("АлгоритмПоиска",                        Новый ОписаниеТипов("Строка"));
	ПравилаКонвертации.Колонки.Добавить("Расширения",                            Новый ОписаниеТипов("Соответствие"));
	ПравилаКонвертации.Колонки.Добавить("ПространствоИмен",                      Новый ОписаниеТипов("Строка"));
	ПравилаКонвертации.Колонки.Добавить("РазрешитьСоздаватьОбъектИзСтруктуры");
	
	Если ВерсияФорматаМенеджераОбмена = "1" Тогда
		ОписаниеТиповСвойстваТЧ = Новый ОписаниеТипов("Структура");
		ПравилаКонвертации.Колонки.Добавить("СвойстваТабличныхЧастейОбработанные", Новый ОписаниеТипов("ТаблицаЗначений"));
	Иначе
		ОписаниеТиповСвойстваТЧ = Новый ОписаниеТипов("ТаблицаЗначений");
	КонецЕсли;
	ПравилаКонвертации.Колонки.Добавить("СвойстваТабличныхЧастей", ОписаниеТиповСвойстваТЧ);
	
	Возврат ПравилаКонвертации;
	
КонецФункции

Функция ТаблицаПравилКонвертации(КомпонентыОбмена)
	
	// Инициализация таблицы правил конвертации.
	ПравилаКонвертации = КоллекцияПравилКонвертации(КомпонентыОбмена.ВерсияФорматаМенеджераОбмена);
	
	КомпонентыОбмена.МенеджерОбмена.ЗаполнитьПравилаКонвертацииОбъектов(КомпонентыОбмена.НаправлениеОбмена, ПравилаКонвертации);
	
	Если КомпонентыОбмена.НаправлениеОбмена = "Получение" Тогда
		
		// Отберем строки правил конвертации, у которых не заполнен реквизит "РазрешитьСоздаватьОбъектИзСтруктуры".
		ПараметрыОтбора = Новый Структура("РазрешитьСоздаватьОбъектИзСтруктуры", Неопределено);
		СтрокиДляОбработки = ПравилаКонвертации.НайтиСтроки(ПараметрыОтбора);
		
		// Для найденных строк необходимо заполнить реквизит "РазрешитьСоздаватьОбъектИзСтруктуры".
		// Реквизит заполняется по следующему алгоритму:
		// если правило конвертации объекта формата не указано
		// в правилах обработки данных для данного объекта формата, 
		// тогда реквизит заполняется значением "Истина", 
		// т.к. полученные по этому ПКО данные не смогут быть загружены самостоятельно,
		// иначе заполняем значением "Ложь".
		Для Каждого СтрокаОбработки Из СтрокиДляОбработки Цикл
			СтрокаОбработки.РазрешитьСоздаватьОбъектИзСтруктуры = Истина;
			СтрокаПравилОбработкиДанных = КомпонентыОбмена.ПравилаОбработкиДанных.Найти(СтрокаОбработки.ОбъектФормата, "ОбъектВыборкиФормат");
			Если СтрокаПравилОбработкиДанных <> Неопределено Тогда
				МассивИспользуемыхПКО = СтрокаПравилОбработкиДанных.ИспользуемыеПКО;
				СтрокаОбработки.РазрешитьСоздаватьОбъектИзСтруктуры = МассивИспользуемыхПКО.Найти(СтрокаОбработки.ИмяПКО) = Неопределено;
			КонецЕсли;
		КонецЦикла;
		
	КонецЕсли;
	
	// Добавляем служебные поля таблицы правил конвертации.
	ПравилаКонвертации.Колонки.Добавить("ТипXDTO");
	ПравилаКонвертации.Колонки.Добавить("ТипСсылкиXDTO");
	ПравилаКонвертации.Колонки.Добавить("ТипКлючевыхСвойствОбъектаXDTO");
	ПравилаКонвертации.Колонки.Добавить("ТипДанных");
	
	ПравилаКонвертации.Колонки.Добавить("МенеджерОбъекта");
	ПравилаКонвертации.Колонки.Добавить("ПолноеИмя");
	
	ПравилаКонвертации.Колонки.Добавить("ЭтоДокумент",               Новый ОписаниеТипов("Булево"));
	ПравилаКонвертации.Колонки.Добавить("ЭтоРегистр",                Новый ОписаниеТипов("Булево"));
	ПравилаКонвертации.Колонки.Добавить("ЭтоСправочник",             Новый ОписаниеТипов("Булево"));
	ПравилаКонвертации.Колонки.Добавить("ЭтоПеречисление",           Новый ОписаниеТипов("Булево"));
	ПравилаКонвертации.Колонки.Добавить("ЭтоПланВидовХарактеристик", Новый ОписаниеТипов("Булево"));
	ПравилаКонвертации.Колонки.Добавить("ЭтоБизнесПроцесс",          Новый ОписаниеТипов("Булево"));
	ПравилаКонвертации.Колонки.Добавить("ЭтоЗадача",                 Новый ОписаниеТипов("Булево"));
	ПравилаКонвертации.Колонки.Добавить("ЭтоПланСчетов",             Новый ОписаниеТипов("Булево"));
	ПравилаКонвертации.Колонки.Добавить("ЭтоПланВидовРасчета",       Новый ОписаниеТипов("Булево"));
	ПравилаКонвертации.Колонки.Добавить("ЭтоКонстанта",              Новый ОписаниеТипов("Булево"));
	
	ПравилаКонвертации.Колонки.Добавить("ДокументМожетПроводиться", Новый ОписаниеТипов("Булево"));
	
	ПравилаКонвертации.Колонки.Добавить("ЭтоСсылочныйТип", Новый ОписаниеТипов("Булево"));
	
	ПравилаКонвертации.Колонки.Добавить("ЕстьОбработчикПриОтправкеДанных",            Новый ОписаниеТипов("Булево"));
	ПравилаКонвертации.Колонки.Добавить("ЕстьОбработчикПриКонвертацииДанныхXDTO",     Новый ОписаниеТипов("Булево"));
	ПравилаКонвертации.Колонки.Добавить("ЕстьОбработчикПередЗаписьюПолученныхДанных", Новый ОписаниеТипов("Булево"));
	ПравилаКонвертации.Колонки.Добавить("ЕстьОбработчикПослеЗагрузкиВсехДанных",      Новый ОписаниеТипов("Булево"));
	ПравилаКонвертации.Колонки.Добавить("ЕстьОбработчикАлгоритмПоиска",               Новый ОписаниеТипов("Булево"));
	
	РазрешитьПроведениеДокумента = Метаданные.СвойстваОбъектов.Проведение.Разрешить;
	
	КоличествоСтрок = ПравилаКонвертации.Количество();
	Для НомерИтерации = 1 По КоличествоСтрок Цикл
		
		ИндексСтроки = КоличествоСтрок - НомерИтерации;
		ПравилоКонвертации = ПравилаКонвертации.Получить(ИндексСтроки);
		
		ЭтоБазоваяСхема  = ЭтоБазоваяСхема(КомпонентыОбмена, ПравилоКонвертации.ПространствоИмен);
		ПространствоИмен = ?(ЭтоБазоваяСхема, КомпонентыОбмена.XMLСхема, ПравилоКонвертации.ПространствоИмен);
		ЕстьРасширения = ПравилоКонвертации.Расширения.Количество() > 0;
		
		Если ЗначениеЗаполнено(ПравилоКонвертации.ОбъектФормата) Тогда
			ПравилоКонвертации.ТипXDTO = ФабрикаXDTO.Тип(ПространствоИмен, ПравилоКонвертации.ОбъектФормата);
			
			Если ПравилоКонвертации.ТипXDTO = Неопределено И ЕстьРасширения Тогда
				ТипXDTOПравилаКонвертацииИзРасширенийПакетаXDTO(ПравилоКонвертации);
			КонецЕсли;
			
			Если ПравилоКонвертации.ТипXDTO = Неопределено Тогда
				ПравилаКонвертации.Удалить(ПравилоКонвертации);
				Продолжить;
			КонецЕсли;
			
		КонецЕсли;
		
		Если ЭтоБазоваяСхема И ЕстьРасширения Тогда
			УдалитьИзбыточныеРасширенияПравилаКонвертации(ПравилоКонвертации);
		КонецЕсли;
		
		Если КомпонентыОбмена.НаправлениеОбмена = "Получение" Тогда
			
			МетаданныеОбъекта = ПравилоКонвертации.ОбъектДанных; // ОбъектМетаданныхСправочник, и др.
		
			ПравилоКонвертации.ИмяТаблицыПолученныхДанных = МетаданныеОбъекта.ПолноеИмя();
			ПравилоКонвертации.ПредставлениеТипаПолученныхДанных = МетаданныеОбъекта.Представление();
			ПравилоКонвертации.ТипПолученныхДанныхСтрокой = ИмяТипаДанныхПоОбъектуМетаданных(ПравилоКонвертации.ОбъектДанных);
		
			ПравилоКонвертации.ПоляПредставленияОбъекта = ?(ПравилоКонвертации.ПоляПоиска.Количество() = 0, "", ПравилоКонвертации.ПоляПоиска[0]);
			
			// Реквизиты объекта получаемых данных.
			РеквизитыМассив = Новый Массив;
			Для Каждого Реквизит Из МетаданныеОбъекта.СтандартныеРеквизиты Цикл
				Если Реквизит.Имя = "Наименование"
					ИЛИ Реквизит.Имя = "Код"
					ИЛИ Реквизит.Имя = "ЭтоГруппа"
					ИЛИ Реквизит.Имя = "Родитель"
					ИЛИ Реквизит.Имя = "Владелец"
					ИЛИ Реквизит.Имя = "Дата"
					ИЛИ Реквизит.Имя = "Номер" Тогда
					РеквизитыМассив.Добавить(Реквизит.Имя);
				КонецЕсли;
			КонецЦикла;
			Для Каждого Реквизит Из МетаданныеОбъекта.Реквизиты Цикл
				РеквизитыМассив.Добавить(Реквизит.Имя);
			КонецЦикла;

			ПравилоКонвертации.РеквизитыШапкиПолученныхДанных = РеквизитыМассив;
			
			ПравилоКонвертации.ЕстьОбработчикПриКонвертацииДанныхXDTO     = Не ПустаяСтрока(ПравилоКонвертации.ПриКонвертацииДанныхXDTO);
			ПравилоКонвертации.ЕстьОбработчикПередЗаписьюПолученныхДанных = Не ПустаяСтрока(ПравилоКонвертации.ПередЗаписьюПолученныхДанных);
			ПравилоКонвертации.ЕстьОбработчикПослеЗагрузкиВсехДанных      = Не ПустаяСтрока(ПравилоКонвертации.ПослеЗагрузкиВсехДанных);
			ПравилоКонвертации.ЕстьОбработчикАлгоритмПоиска               = Не ПустаяСтрока(ПравилоКонвертации.АлгоритмПоиска);
		Иначе
			ПравилоКонвертации.ЕстьОбработчикПриОтправкеДанных            = Не ПустаяСтрока(ПравилоКонвертации.ПриОтправкеДанных);
		КонецЕсли;
		
		Если ПравилоКонвертации.ОбъектДанных <> Неопределено Тогда
			
			ПравилоКонвертации.ПолноеИмя                  = ПравилоКонвертации.ОбъектДанных.ПолноеИмя();
			ПравилоКонвертации.МенеджерОбъекта            = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПравилоКонвертации.ПолноеИмя);
			
			ПравилоКонвертации.ЭтоРегистр = Ложь;
			ПравилоКонвертации.ЭтоДокумент = Ложь;
			ПравилоКонвертации.ЭтоСправочник = Ложь;
			ПравилоКонвертации.ЭтоПеречисление = Ложь;
			ПравилоКонвертации.ЭтоПланВидовХарактеристик = Ложь;
			ПравилоКонвертации.ЭтоБизнесПроцесс = Ложь;
			ПравилоКонвертации.ЭтоЗадача = Ложь;
			ПравилоКонвертации.ЭтоПланСчетов = Ложь;
			ПравилоКонвертации.ЭтоПланВидовРасчета = Ложь;
			ПравилоКонвертации.ЭтоКонстанта = Ложь;
	
			Если ОбменДаннымиПовтИсп.ЭтоСправочник(ПравилоКонвертации.ПолноеИмя) Тогда
				ПравилоКонвертации.ЭтоСправочник = Истина;
			ИначеЕсли ОбменДаннымиПовтИсп.ЭтоДокумент(ПравилоКонвертации.ПолноеИмя) Тогда
				ПравилоКонвертации.ЭтоДокумент = Истина;
			ИначеЕсли ОбменДаннымиПовтИсп.ЭтоПеречисление(ПравилоКонвертации.ПолноеИмя) Тогда
				ПравилоКонвертации.ЭтоПеречисление = Истина;
			ИначеЕсли ОбменДаннымиПовтИсп.ЭтоРегистр(ПравилоКонвертации.ПолноеИмя) Тогда
				ПравилоКонвертации.ЭтоРегистр = Истина;
			ИначеЕсли ОбменДаннымиПовтИсп.ЭтоПланВидовХарактеристик(ПравилоКонвертации.ПолноеИмя) Тогда
				ПравилоКонвертации.ЭтоПланВидовХарактеристик = Истина;
			ИначеЕсли ОбменДаннымиПовтИсп.ЭтоБизнесПроцесс(ПравилоКонвертации.ПолноеИмя) Тогда
				ПравилоКонвертации.ЭтоБизнесПроцесс = Истина;
			ИначеЕсли ОбменДаннымиПовтИсп.ЭтоЗадача(ПравилоКонвертации.ПолноеИмя) Тогда
				ПравилоКонвертации.ЭтоЗадача = Истина;
			ИначеЕсли ОбменДаннымиПовтИсп.ЭтоПланСчетов(ПравилоКонвертации.ПолноеИмя) Тогда
				ПравилоКонвертации.ЭтоПланСчетов = Истина;
			ИначеЕсли ОбменДаннымиПовтИсп.ЭтоПланВидовРасчета(ПравилоКонвертации.ПолноеИмя) Тогда
				ПравилоКонвертации.ЭтоПланВидовРасчета = Истина;
			ИначеЕсли ОбменДаннымиПовтИсп.ЭтоКонстанта(ПравилоКонвертации.ПолноеИмя) Тогда
				ПравилоКонвертации.ЭтоКонстанта = Истина;
			КонецЕсли;
			
			ПравилоКонвертации.ТипДанных = Тип(ИмяТипаДанныхПоОбъектуМетаданных(ПравилоКонвертации.ОбъектДанных));
			
			Если ПравилоКонвертации.ЭтоДокумент Тогда
				ПравилоКонвертации.ДокументМожетПроводиться = ПравилоКонвертации.ОбъектДанных.Проведение = РазрешитьПроведениеДокумента;
			КонецЕсли;
			
		КонецЕсли;
		
		ПравилоКонвертации.ЭтоСсылочныйТип = ПравилоКонвертации.ЭтоДокумент
			Или ПравилоКонвертации.ЭтоСправочник
			Или ПравилоКонвертации.ЭтоПланВидовХарактеристик
			Или ПравилоКонвертации.ЭтоБизнесПроцесс
			Или ПравилоКонвертации.ЭтоЗадача
			Или ПравилоКонвертации.ЭтоПланСчетов
			Или ПравилоКонвертации.ЭтоПланВидовРасчета;
		
		ОтметитьКлючевыеСвойстваПравилаКонвертации(КомпонентыОбмена, ПравилоКонвертации);
		
		Если ПравилоКонвертации.ВариантИдентификации = "ПоПолямПоиска"
			Или ПравилоКонвертации.ВариантИдентификации = "СначалаПоУникальномуИдентификаторуПотомПоПолямПоиска" Тогда
			
			ТаблицаПКС = ПравилоКонвертации.Свойства;
			Для Каждого ПКС Из ТаблицаПКС Цикл
				
				Если ЗначениеЗаполнено(ПравилоКонвертации.ПоляПоиска) Тогда
					Для Каждого ЭлементПолейПоиска Из ПравилоКонвертации.ПоляПоиска Цикл
						ПоляПоискаМассивом = СтрРазделить(ЭлементПолейПоиска, ",");
						Для Каждого ПолеПоиска Из ПоляПоискаМассивом Цикл
							ПолеПоиска = СокрЛП(ПолеПоиска);
							Если ПолеПоиска = ПКС.СвойствоКонфигурации Тогда
								ПКС.ОбработкаПоисковогоСвойства = Истина;
								Прервать;
							КонецЕсли;
						КонецЦикла;
					КонецЦикла;
				КонецЕсли;
				
			КонецЦикла;
			
		КонецЕсли;
		
		Если КомпонентыОбмена.ВерсияФорматаМенеджераОбмена = "1" Тогда
			ИнициализироватьСвойстваТабличныхЧастей(ПравилоКонвертации, "СвойстваТабличныхЧастейОбработанные");
			Для Каждого ТЧ Из ПравилоКонвертации.СвойстваТабличныхЧастей Цикл
				СтрокаСвойстваТабличныхЧастей = ПравилоКонвертации.СвойстваТабличныхЧастейОбработанные.Добавить();
				СтрокаСвойстваТабличныхЧастей.ИспользуетсяАлгоритмКонвертации = Истина;
				СтрокаСвойстваТабличныхЧастей.Свойства = ТЧ.Значение;
				Если КомпонентыОбмена.НаправлениеОбмена = "Получение" Тогда
					СтрокаСвойстваТабличныхЧастей.ТЧКонфигурации = ТЧ.Ключ;
				Иначе
					СтрокаСвойстваТабличныхЧастей.ТЧФормата = ТЧ.Ключ;
				КонецЕсли;
			КонецЦикла;
		Иначе
			// Заполнение информации о конвертации свойств табличных частей.
			Для Каждого ПКСТЧ Из ПравилоКонвертации.СвойстваТабличныхЧастей Цикл
				Для Каждого ПКС Из ПКСТЧ.Свойства Цикл
					Если ПКС.ИспользуетсяАлгоритмКонвертации Тогда
						ПКСТЧ.ИспользуетсяАлгоритмКонвертации = Истина;
						Прервать;
					КонецЕсли;
				КонецЦикла;
			КонецЦикла;
		КонецЕсли;
	КонецЦикла;
	
	Если КомпонентыОбмена.ВерсияФорматаМенеджераОбмена = "1" Тогда
		ПравилаКонвертации.Колонки.Удалить(ПравилаКонвертации.Колонки.СвойстваТабличныхЧастей);
		ПравилаКонвертации.Колонки.Добавить("СвойстваТабличныхЧастей", Новый ОписаниеТипов("ТаблицаЗначений"));
		Для Каждого ПравилоКонвертации Из ПравилаКонвертации Цикл
			ИнициализироватьСвойстваТабличныхЧастей(ПравилоКонвертации);
			Для Каждого СвойствоТЧ Из ПравилоКонвертации.СвойстваТабличныхЧастейОбработанные Цикл
				СтрокаСвойстваТабличныхЧастей = ПравилоКонвертации.СвойстваТабличныхЧастей.Добавить();
				ЗаполнитьЗначенияСвойств(СтрокаСвойстваТабличныхЧастей, СвойствоТЧ);
				Для Каждого ПКС Из СтрокаСвойстваТабличныхЧастей.Свойства Цикл
					Если ПКС.ИспользуетсяАлгоритмКонвертации Тогда
						СтрокаСвойстваТабличныхЧастей.ИспользуетсяАлгоритмКонвертации = Истина;
						Прервать;
					КонецЕсли;
				КонецЦикла;
			КонецЦикла;
		КонецЦикла;
		ПравилаКонвертации.Колонки.Удалить(ПравилаКонвертации.Колонки.СвойстваТабличныхЧастейОбработанные);
	КонецЕсли;
	
	// Добавляем индексы таблицы правил конвертации.
	ПравилаКонвертации.Индексы.Добавить("ИмяПКО");
	ПравилаКонвертации.Индексы.Добавить("ТипДанных");
	ПравилаКонвертации.Индексы.Добавить("ТипXDTO");
	Если КомпонентыОбмена.НаправлениеОбмена = "Получение" Тогда
		ПравилаКонвертации.Индексы.Добавить("ТипСсылкиXDTO");
	КонецЕсли;
	
	Возврат ПравилаКонвертации;
	
КонецФункции

Функция ТаблицаПравилКонвертацииПредопределенныхДанных(КомпонентыОбмена)
	
	XMLСхема = КомпонентыОбмена.XMLСхема;
	ВерсияФорматаМенеджераОбмена = КомпонентыОбмена.ВерсияФорматаМенеджераОбмена;
	
	// Инициализация таблицы правил конвертации.
	ПравилаКонвертации = Новый ТаблицаЗначений;
	ПравилаКонвертации.Колонки.Добавить("ТипДанных");
	ПравилаКонвертации.Колонки.Добавить("ТипXDTO");
	ПравилаКонвертации.Колонки.Добавить("КонвертацииЗначенийПриПолучении");
	ПравилаКонвертации.Колонки.Добавить("КонвертацииЗначенийПриОтправке");
	
	ПравилаКонвертации.Колонки.Добавить("ИмяПКПД", Новый ОписаниеТипов("Строка"));
	
	КомпонентыОбмена.МенеджерОбмена.ЗаполнитьПравилаКонвертацииПредопределенныхДанных(КомпонентыОбмена.НаправлениеОбмена, ПравилаКонвертации);

	ТранслироватьПредопределенныеданные(ПравилаКонвертации);
	
	Для Каждого ПравилоКонвертации Из ПравилаКонвертации Цикл
		ПравилоКонвертации.ТипXDTO = ФабрикаXDTO.Тип(XMLСхема, ПравилоКонвертации.ТипXDTO);
		ПравилоКонвертации.ТипДанных = Тип(ИмяТипаДанныхПоОбъектуМетаданных(ПравилоКонвертации.ТипДанных));
	КонецЦикла;
	
	ПравилаКонвертации.Индексы.Добавить("ИмяПКПД");
	ПравилаКонвертации.Индексы.Добавить("ТипДанных");
	ПравилаКонвертации.Индексы.Добавить("ТипДанных,ТипXDTO");
	
	Возврат ПравилаКонвертации;
	
КонецФункции

Функция СтруктураПараметровКонвертации(МенеджерОбмена)
	// Инициализация структуры с параметрами конвертации.
	//	Возможно, в будущем понадобится не структура, а таблица (если потребуется передавать параметры из одной базы в
	//	другую).
	ПараметрыКонвертации = Новый Структура();
	МенеджерОбмена.ЗаполнитьПараметрыКонвертации(ПараметрыКонвертации);
	Возврат ПараметрыКонвертации;
КонецФункции

Процедура ПослеИнициализацииКомпонентыОбмена(КомпонентыОбмена) Экспорт
	
	Если ТипЗнч(КомпонентыОбмена) <> Тип("Структура") Тогда
		
		Возврат;
		
	КонецЕсли;
	
	// В некоторых случаях уже на этапе обработки данных необходимо понимать
	// проходит объект расширенную проверку, например, по дате запрета загрузки данных в период.
	// Для этого необходимо иметь возможность обратиться к УзлуПланаОбмена как Объекту ИБ.
	Если КомпонентыОбмена.Свойство("ЭтоОбменЧерезПланОбмена")
		И КомпонентыОбмена.Свойство("УзелКорреспондента")
		И КомпонентыОбмена.Свойство("УзелКорреспондентаОбъект") Тогда
		
		Если КомпонентыОбмена.ЭтоОбменЧерезПланОбмена = Истина
			И ЗначениеЗаполнено(КомпонентыОбмена.УзелКорреспондента)
			И КомпонентыОбмена.УзелКорреспондентаОбъект = Неопределено Тогда
			
			КомпонентыОбмена.УзелКорреспондентаОбъект = КомпонентыОбмена.УзелКорреспондента.ПолучитьОбъект();
			
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

// АПК:299-выкл - Вызывается из правил
Процедура ИнициализироватьРасширениеПравилаКонвертацииОбъекта(ПравилоКонвертации, Знач ПространствоИмен) Экспорт
	
	СтруктураРасширенияПравилаКонвертацииОбъекта = Новый Структура;
	СтруктураРасширенияПравилаКонвертацииОбъекта.Вставить("ТипXDTO");
	СтруктураРасширенияПравилаКонвертацииОбъекта.Вставить("ТипКлючевыхСвойствОбъектаXDTO");
	СтруктураРасширенияПравилаКонвертацииОбъекта.Вставить("ТипДанных");
	
	ПравилоКонвертации.Расширения.Вставить(ПространствоИмен, СтруктураРасширенияПравилаКонвертацииОбъекта);
	
КонецПроцедуры
// АПК:299-вкл

Процедура ТипXDTOПравилаОбработкиИзРасширенийПакетаXDTO(КомпонентыОбмена, ПОД, ТипXDTO)
	
	Для каждого ОписаниеРасширения Из КомпонентыОбмена.РасширенияФормата Цикл
		
		ПространствоИменРасширения = ОписаниеРасширения.Ключ;
		ТипРасширенияXDTO = ФабрикаXDTO.Тип(ПространствоИменРасширения, ПОД.ОбъектВыборкиФормат);
		Если ТипРасширенияXDTO <> Неопределено Тогда
			
			// Установили пренадлежность к расширению схемы XDTO
			ТипXDTO = ТипРасширенияXDTO;
			Прервать;
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

Процедура ТипXDTOПравилаКонвертацииИзРасширенийПакетаXDTO(ПравилоКонвертации)
	
	Для каждого РасширениеФорматаИзПравилаКонвертации Из ПравилоКонвертации.Расширения Цикл
		
		ПространствоИменРасширения = РасширениеФорматаИзПравилаКонвертации.Ключ;
		ПравилоКонвертации.ТипXDTO = ФабрикаXDTO.Тип(ПространствоИменРасширения, ПравилоКонвертации.ОбъектФормата);
		Если ПравилоКонвертации.ТипXDTO <> Неопределено Тогда
			
			// Установили пренадлежность к расширению схемы XDTO
			Прервать;
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

Процедура УдалитьИзбыточныеРасширенияПравилаКонвертации(ПравилоКонвертации)
	
	РасширенияКУдалению = Новый Массив;
	Для Каждого РасширениеПакетаXDTO Из ПравилоКонвертации.Расширения Цикл
		
		ПространствоИменРасширенияФормата = РасширениеПакетаXDTO.Ключ;
		
		ТипXDTO = ФабрикаXDTO.Тип(ПространствоИменРасширенияФормата, ПравилоКонвертации.ОбъектФормата);
		Если ТипXDTO = Неопределено Тогда
			
			РасширенияКУдалению.Добавить(ПространствоИменРасширенияФормата);
			
		Иначе
			
			РасширениеПакетаXDTO.Значение.ТипXDTO = ТипXDTO;
			
		КонецЕсли;
		
	КонецЦикла;
	
	Для Каждого РасширениеКУдалению Из РасширенияКУдалению Цикл
		
		ПравилоКонвертации.Расширения.Удалить(РасширениеКУдалению);
		
	КонецЦикла;
	
КонецПроцедуры
// АПК:299-вкл

Процедура ОтметитьКлючевыеСвойстваПравилаКонвертации(КомпонентыОбмена, ПравилоКонвертации)
	
	Если НЕ ЗначениеЗаполнено(ПравилоКонвертации.ОбъектФормата) Тогда
		
		Возврат;
		
	КонецЕсли;
	
	КлючевыеСвойства = ПравилоКонвертации.ТипXDTO.Свойства.Получить(КлассКлючевыеСвойстваФормата());
	Если КлючевыеСвойства = Неопределено Тогда
		
		Возврат;
		
	КонецЕсли;
	
	ТипКлючевыхСвойствОбъектаXDTO = КлючевыеСвойства.Тип;
	ПравилоКонвертации.ТипКлючевыхСвойствОбъектаXDTO = ТипКлючевыхСвойствОбъектаXDTO;
	
	МассивКлючевыхСвойств = Новый Массив;
	ЗаполнитьСписокСвойствОбъектаXDTO(ТипКлючевыхСвойствОбъектаXDTO, МассивКлючевыхСвойств);
	ДополнитьКлючевыеСвойстваПакетаИзРасширений(ПравилоКонвертации, ТипКлючевыхСвойствОбъектаXDTO, МассивКлючевыхСвойств);
	
	ПКСДляДобавления = Новый Массив;
	
	ТаблицаПКС = ПравилоКонвертации.Свойства;
	Для Каждого ПКС Из ТаблицаПКС Цикл
		
		СвойствоФормата = ТранслироватьИмя(ПКС.СвойствоФормата, "ru", ПравилоКонвертации.ТипXDTO);
		
		Если МассивКлючевыхСвойств.Найти(СвойствоФормата) <> Неопределено Тогда
			ПКС.ОбработкаКлючевогоСвойства = Истина;
			
			Если ПравилоКонвертации.ТипXDTO.Свойства.Получить(СвойствоФормата) <> Неопределено Тогда
				ПКСДляДобавления.Добавить(ПКС);
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЦикла;
	
	Для Каждого ПКС Из ПКСДляДобавления Цикл
		НовоеПКС = ТаблицаПКС.Добавить();
		ЗаполнитьЗначенияСвойств(НовоеПКС, ПКС, , "ОбработкаКлючевогоСвойства");
	КонецЦикла;
	
	СвойствоСсылкаXDTO = ТипКлючевыхСвойствОбъектаXDTO.Свойства.Получить(КлассСсылкаФормата());
	Если СвойствоСсылкаXDTO <> Неопределено Тогда
		
		ПравилоКонвертации.ТипСсылкиXDTO = СвойствоСсылкаXDTO.Тип;
		
		Если ПравилоКонвертации.ЭтоСсылочныйТип
			И КомпонентыОбмена.НаправлениеОбмена = "Отправка" Тогда
			ПКСДляСсылки = ТаблицаПКС.Добавить();
			ПКСДляСсылки.СвойствоКонфигурации = КлассСсылка();
			ПКСДляСсылки.СвойствоФормата = КлассСсылка();
			ПКСДляСсылки.ОбработкаКлючевогоСвойства = Истина;
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область ОтправкаДанных

Процедура ДополнитьОбъектXDTO(ОбъектXDTO, Знач Свойство, Знач Значение)
	
	Если Не ОбщегоНазначенияКлиентСервер.ЕстьРеквизитИлиСвойствоОбъекта(ОбъектXDTO, Свойство.Имя) Тогда
		
		ОбъектXDTO.Добавить(Свойство.Форма, Свойство.URIПространстваИмен, Свойство.Имя, Значение);
		Возврат;
		
	КонецЕсли;
	
	Если ЭтоТаблицаОбъекта(Свойство) Тогда
		ИмяСвойстваСтроки = Свойство.Тип.Свойства[0].Имя;
		Для ИндексСтроки = 0 По Значение[ИмяСвойстваСтроки].Количество() - 1 Цикл
			СтрокаXDTO = ОбъектXDTO[Свойство.Имя][ИмяСвойстваСтроки].Получить(ИндексСтроки); // ОбъектXDTO 
			РасширениеСтрокиXDTO = Значение[ИмяСвойстваСтроки].Получить(ИндексСтроки);
			
			Для Каждого СвойствоСтроки Из РасширениеСтрокиXDTO.Свойства() Цикл
				Если ТипЗнч(СвойствоСтроки.Тип) = Тип("ТипЗначенияXDTO") Тогда
					ЗначениеСвойстваСтроки = ФабрикаXDTO.Создать(СвойствоСтроки.Тип,
						РасширениеСтрокиXDTO.Получить(СвойствоСтроки.Имя));
				Иначе
					ЗначениеСвойстваСтроки = РасширениеСтрокиXDTO.Получить(СвойствоСтроки.Имя);
				КонецЕсли;

				Если ЗначениеСвойстваСтроки = Неопределено Тогда
					Продолжить;
				КонецЕсли;
				
				СтрокаXDTO.Добавить(
					СвойствоСтроки.Форма,
					СвойствоСтроки.URIПространстваИмен,
					СвойствоСтроки.Имя,
					ЗначениеСвойстваСтроки);
			КонецЦикла;
		КонецЦикла;
	ИначеЕсли ТипЗнч(Свойство.Тип) = Тип("ТипОбъектаXDTO") Тогда
		Для Каждого ДочернееСвойство Из Значение.Свойства() Цикл
			Подзначение = Значение.Получить(ДочернееСвойство.Имя);
			Если Подзначение = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			
			Если ТипЗнч(ДочернееСвойство.Тип) = Тип("ТипЗначенияXDTO") Тогда
				ДополнитьОбъектXDTO(ОбъектXDTO[Свойство.Имя], ДочернееСвойство, 
					ФабрикаXDTO.Создать(ДочернееСвойство.Тип, Подзначение));
			Иначе
				ДополнитьОбъектXDTO(ОбъектXDTO[Свойство.Имя], ДочернееСвойство, Подзначение);
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;

КонецПроцедуры

Процедура ВыполнитьВыгрузкуЗарегистрированныхДанных(КомпонентыОбмена, НомерСообщения)
		
	УзелДляОбмена = КомпонентыОбмена.УзелКорреспондента;
	УзелДляОбменаОбъект = УзелДляОбмена.ПолучитьОбъект();
	
	// Предварительная очистка регистрации
	ИменаОбъектовМетаданных = ОбменДаннымиВызовСервера.ИменаМетаданныхНеВыгружаемыхОбъектовУзла(УзелДляОбмена);
	Для Каждого Имя Из ИменаОбъектовМетаданных Цикл
		ОбъектМетаданных = Метаданные.НайтиПоПолномуИмени(Имя);
		ПланыОбмена.УдалитьРегистрациюИзменений(УзелДляОбмена, ОбъектМетаданных);
	КонецЦикла;
	
	НачальнаяВыгрузкаДанных = ОбменДаннымиСервер.УстановленПризнакНачальнойВыгрузкиДанных(УзелДляОбмена);
	КоличествоОбъектовКВыгрузке = 0;
	ТаблицаИзменений = ЗаполнитьТаблицуИзменений(УзелДляОбмена, НомерСообщения, КоличествоОбъектовКВыгрузке);
		
	КомпонентыОбмена.Вставить("КоличествоОбъектовКВыгрузке", КоличествоОбъектовКВыгрузке);
		
	//  Алгоритм выгрузки данных в XML-файл:
	// 1. Получаем Данные из ИБ
	// 2. Отправляем информацию об удалении либо выгружаем данные.
	// 3. Конвертируем Данные в Структуру по правилу конвертации.
	// 4. Конвертируем Данные в Структуру в обработчике ПриОтправкеДанных.
	// 5. Конвертируем Структуру в ОбъектXDTO.
	// 6. Записываем ОбъектXDTO в XML-файл.
	Для Каждого СтрокаИзменений Из ТаблицаИзменений Цикл
		
		ПараметрыПР = ОбменДаннымиСобытия.ПараметрыПакетнойРегистрации();
		ПараметрыПР.СозданиеНачальногоОбраза = НачальнаяВыгрузкаДанных;
		
		Если СтрокаИзменений.ЕстьПравилоПакетнойРегистрации Тогда
			
			ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер(); 
			
			ОбменДаннымиСобытия.ВыполнитьПакетнуюРегистрациюДляУзла(УзелДляОбмена, СтрокаИзменений.МассивДанных, ПараметрыПР);
			
			ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
				ВремяНачала, "ПакетнаяРегистрацияОбъектов", СтрокаИзменений.Тип, КомпонентыОбмена,
				ОбменДаннымиОценкаПроизводительности.ТипСобытияПрикладное());
				
		КонецЕсли;
				
		Для Каждого Данные Из СтрокаИзменений.МассивДанных Цикл
						
			Попытка
				Если ТипЗнч(Данные) = Тип("УдалениеОбъекта") Тогда
					ВыгрузитьУдаление(КомпонентыОбмена, Данные.Ссылка);
				Иначе
					
					ЭтоСсылка = СтрокаИзменений.ЕстьПравилоПакетнойРегистрации;
					
					ОтправкаЭлемента = ОтправкаЭлементаДанных.Авто;
					
					ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
					
					Если СтрокаИзменений.ЕстьПравилоПакетнойРегистрации Тогда
						
						Если ПараметрыПР.ЕстьПРО_БезПакетнойРегистрации 
							И ПараметрыПР.СсылкиПоФильтруПакетнойРегистрации.Найти(Данные) = Неопределено Тогда
							
							ЭлементДанных = ?(ЭтоСсылка, Данные.ПолучитьОбъект(), Данные);
							ЭлементДанных.ДополнительныеСвойства.Вставить("ПроверкаРегистрацииПередВыгрузкой");
							ОбменДаннымиСобытия.ПриОтправкеДанныхКорреспонденту(ЭлементДанных, ОтправкаЭлемента, 
								НачальнаяВыгрузкаДанных, УзелДляОбменаОбъект, Ложь);
								
						ИначеЕсли Не ПараметрыПР.ЕстьПРО_БезПакетнойРегистрации 
							И ПараметрыПР.СсылкиПоФильтруПакетнойРегистрации.Найти(Данные.Ссылка) = Неопределено Тогда 
							
							Если НачальнаяВыгрузкаДанных Тогда
								ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать;
							Иначе
								ОтправкаЭлемента = ОтправкаЭлементаДанных.Удалить;
							КонецЕсли;
							
						КонецЕсли;
						
					Иначе
						
						ЭлементДанных = ?(ЭтоСсылка, Данные.ПолучитьОбъект(), Данные);
						ЭлементДанных.ДополнительныеСвойства.Вставить("ПроверкаРегистрацииПередВыгрузкой");
						ОбменДаннымиСобытия.ПриОтправкеДанныхКорреспонденту(ЭлементДанных, ОтправкаЭлемента, 
							НачальнаяВыгрузкаДанных, УзелДляОбменаОбъект, Ложь);
						
					КонецЕсли;
						
					ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
						ВремяНачала, "РегистрацияОбъектов", Данные, КомпонентыОбмена,
						ОбменДаннымиОценкаПроизводительности.ТипСобытияБиблиотека());
					
					// Удаление регистра отсылаем в виде пустого набора записей.
					Если ОтправкаЭлемента = ОтправкаЭлементаДанных.Удалить
						И ОбщегоНазначения.ЭтоРегистр(Данные.Метаданные()) Тогда
						ОтправкаЭлемента = ОтправкаЭлементаДанных.Авто;
					КонецЕсли;
					
					Если ОтправкаЭлемента = ОтправкаЭлементаДанных.Удалить Тогда
						ВыгрузитьУдаление(КомпонентыОбмена, Данные.Ссылка);
					ИначеЕсли ОтправкаЭлемента = ОтправкаЭлементаДанных.Игнорировать Тогда
						// Ситуация, когда объект не соответствует условиям фильтра, но его не нужно отправлять как удаление.
						// Возникает в случае первоначальной выгрузки данных.
						ПланыОбмена.УдалитьРегистрациюИзменений(УзелДляОбмена, Данные);
						Продолжить;
					Иначе
						ЭлементДанных = ?(ЭтоСсылка, Данные.ПолучитьОбъект(), Данные);
						ВыгрузкаОбъектаВыборки(КомпонентыОбмена, ЭлементДанных);
					КонецЕсли;
				КонецЕсли;
				
				КомпонентыОбмена.СчетчикВыгруженныхОбъектов = КомпонентыОбмена.СчетчикВыгруженныхОбъектов + 1;
				ОбменДаннымиСервер.РассчитатьПроцентВыгрузки(КомпонентыОбмена.СчетчикВыгруженныхОбъектов, КомпонентыОбмена.КоличествоОбъектовКВыгрузке);
				
			Исключение
				Инфо = ИнформацияОбОшибке();
				ПредставлениеДанных = ПредставлениеОбъектаДляПротокола(Данные);
				
				ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Событие: %1.
					|Объект: %2.
					|
					|%3'"),
					КомпонентыОбмена.НаправлениеОбмена,
					ПредставлениеДанных,
					ОбработкаОшибок.ПодробноеПредставлениеОшибки(Инфо));
				КонецПопытки;
				
		КонецЦикла;
		
	КонецЦикла;
	
КонецПроцедуры

Функция ЗаполнитьТаблицуИзменений(УзелДляОбмена, НомерСообщения, КоличествоОбъектовКВыгрузке)
	
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелДляОбмена);
	
	// Получаем выборку измененных данных.
	ВыборкаИзменений = ПланыОбмена.ВыбратьИзменения(УзелДляОбмена, НомерСообщения);
		
	ТаблицаИзменений = Новый ТаблицаЗначений;
	ТаблицаИзменений.Колонки.Добавить("Тип");
	ТаблицаИзменений.Колонки.Добавить("МассивДанных", Новый ОписаниеТипов("Массив"));
	ТаблицаИзменений.Колонки.Добавить("ЕстьПравилоПакетнойРегистрации", Новый ОписаниеТипов("Булево"));
		
	Пока ВыборкаИзменений.Следующий() Цикл
		
		КоличествоОбъектовКВыгрузке = КоличествоОбъектовКВыгрузке + 1;
		
		Данные = ВыборкаИзменений.Получить();
		Тип = ТипЗнч(Данные);
		СтрокаИзменений = ТаблицаИзменений.Найти(Тип, "Тип");
		
		Если СтрокаИзменений = Неопределено Тогда 
			
			СтрокаИзменений = ТаблицаИзменений.Добавить();
			СтрокаИзменений.Тип = Тип;
			СтрокаИзменений.ЕстьПравилоПакетнойРегистрации = ЕстьПравилоПакетнойРегистрации(Данные, УзелДляОбмена);
			
		КонецЕсли;
		
		Если СтрокаИзменений.ЕстьПравилоПакетнойРегистрации Тогда 
			СтрокаИзменений.МассивДанных.Добавить(Данные.Ссылка);
		Иначе
			СтрокаИзменений.МассивДанных.Добавить(Данные);
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат ТаблицаИзменений;
	
КонецФункции

Функция ЕстьПравилоПакетнойРегистрации(Данные, Узел)
	
	Тип = ТипЗнч(Данные);
	
	Если Тип = Тип("УдалениеОбъекта") Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Результат = Ложь;
	Если ОбщегоНазначения.ЭтоОбъектСсылочногоТипа(Данные.Метаданные()) Тогда
		
		ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(Узел);
		ПолноеИмяОбъекта = Данные.Метаданные().ПолноеИмя();
		
		Правила = ОбменДаннымиСобытия.ПравилаРегистрацииОбъекта(ИмяПланаОбмена, ПолноеИмяОбъекта);
			
		Для Каждого ПРО Из Правила Цикл
			Если ПРО.ПакетноеВыполнениеОбработчиков Тогда
				Результат = Истина;
				Прервать;
			КонецЕсли;
		КонецЦикла;
		
	КонецЕсли;
		
	Возврат Результат;
	
КонецФункции

Процедура ВыгрузитьОбъектыПоСсылке(КомпонентыОбмена, СсылкиИзОбъекта)
	
	Если Не КомпонентыОбмена.ЭтоОбменЧерезПланОбмена Тогда
		Возврат;
	КонецЕсли;
			
	Для Каждого ЗначениеСсылки Из СсылкиИзОбъекта Цикл
		
		Если КомпонентыОбмена.ВыгруженныеОбъекты.Найти(ЗначениеСсылки) = Неопределено
			И ВыгружатьОбъектПоНеобходимости(КомпонентыОбмена, ЗначениеСсылки) Тогда
			
			Если Не РегистрыСведений.ДанныеОбъектовДляРегистрацииВОбменах.ОбъектЕстьВРегистре(
				ЗначениеСсылки, КомпонентыОбмена.УзелКорреспондента) Тогда
				
				ОбъектВыгружаемыйПоСсылке = Неопределено;
				
				Если ОбщегоНазначения.СсылкаСуществует(ЗначениеСсылки) Тогда
					ОбъектВыгружаемыйПоСсылке = ЗначениеСсылки.ПолучитьОбъект();
				КонецЕсли;
				
				Если ОбъектВыгружаемыйПоСсылке <> Неопределено Тогда
					
					ВыгрузкаОбъектаВыборки(КомпонентыОбмена, ОбъектВыгружаемыйПоСсылке);
					КомпонентыОбмена.ВыгруженныеПоСсылкеОбъекты.Добавить(ЗначениеСсылки);
					РегистрыСведений.ДанныеОбъектовДляРегистрацииВОбменах.ДобавитьОбъектВФильтрРазрешенныхОбъектов(
						ЗначениеСсылки, КомпонентыОбмена.УзелКорреспондента);
					
				КонецЕсли;
				
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

Функция ЭтоСсылкаXDTO(Знач Тип)
	
	Возврат ФабрикаXDTO.Тип(XMLБазоваяСхема(), "Ref").ЭтоПотомок(Тип);
	
КонецФункции

Функция ВыгружатьОбъектПоНеобходимости(КомпонентыОбмена, Объект)
	
	ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипЗнч(Объект));
	
	Если ОбъектМетаданных = Неопределено Тогда
		Возврат Ложь;
	КонецЕсли;
	
	// Получаем настройку из КЭШа
	РегистрацияПоНеобходимости = КомпонентыОбмена.СоответствиеРегистрацияПоНеобходимости.Получить(ОбъектМетаданных);
	Если РегистрацияПоНеобходимости <> Неопределено Тогда
		Возврат РегистрацияПоНеобходимости;
	КонецЕсли;
	
	РегистрацияПоНеобходимости = Ложь;
	
	Отбор = Новый Структура("ОбъектМетаданныхИмя", ОбъектМетаданных.ПолноеИмя());
	МассивПравил = КомпонентыОбмена.ТаблицаПравилаРегистрацииОбъектов.НайтиСтроки(Отбор);
	
	Для Каждого Правило Из МассивПравил Цикл
		
		Если Не ПустаяСтрока(Правило.ИмяРеквизитаФлага) Тогда
			
			ЗначениеРеквизитаФлага = Неопределено;
			КомпонентыОбмена.СвойстваУзлаПланаОбмена.Свойство(Правило.ИмяРеквизитаФлага, ЗначениеРеквизитаФлага);
			
			РегистрацияПоНеобходимости = (ЗначениеРеквизитаФлага = Перечисления.РежимыВыгрузкиОбъектовОбмена.ВыгружатьПриНеобходимости
				Или ЗначениеРеквизитаФлага = Перечисления.РежимыВыгрузкиОбъектовОбмена.ПустаяСсылка());

			Если РегистрацияПоНеобходимости Тогда
				Прервать;
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЦикла;
	
	// Сохраняем полученное значение в кэше.
	КомпонентыОбмена.СоответствиеРегистрацияПоНеобходимости.Вставить(ОбъектМетаданных, РегистрацияПоНеобходимости);
	Возврат РегистрацияПоНеобходимости;
	
КонецФункции

Процедура ЗаписатьУдалениеОбъектаXDTO(КомпонентыОбмена, Ссылка, ТипСсылкиXDTO)
	
	УИДОбъектаXDTO = РегистрыСведений.ПубличныеИдентификаторыСинхронизируемыхОбъектов.ПубличныйИдентификаторПоСсылкеОбъекта(
		КомпонентыОбмена.УзелКорреспондента, Ссылка);
		
	Если Не ЗначениеЗаполнено(УИДОбъектаXDTO) Тогда
		Возврат;
	КонецЕсли;
	
	XMLСхема = КомпонентыОбмена.XMLСхема;
	ТипXDTO  = ФабрикаXDTO.Тип(XMLСхема, "УдалениеОбъекта");
	
	Для Каждого Свойство Из ТипXDTO.Свойства[0].Тип.Свойства[0].Тип.Свойства Цикл
		Если Свойство.Тип = ТипСсылкиXDTO Тогда
			
			ЗначениеXDTOЛюбаяСсылка = ФабрикаXDTO.Создать(Свойство.Тип, УИДОбъектаXDTO);
			
			СсылкаНаОбъект = ФабрикаXDTO.Создать(ТипXDTO.Свойства[0].Тип.Свойства[0].Тип); // ОбъектXDTO
			СсылкаНаОбъект.Установить(Свойство, ЗначениеXDTOЛюбаяСсылка);
			
			ЛюбаяСсылкаОбъект = ФабрикаXDTO.Создать(ТипXDTO.Свойства[0].Тип);
			ЛюбаяСсылкаОбъект.СсылкаНаОбъект = СсылкаНаОбъект;
			
			ДанныеXDTO = ФабрикаXDTO.Создать(ТипXDTO); // ОбъектXDTO
			ДанныеXDTO.СсылкаНаОбъект = ФабрикаXDTO.Создать(ТипXDTO.Свойства[0].Тип);
			ДанныеXDTO.Установить(ТипXDTO.Свойства[0], ЛюбаяСсылкаОбъект);
			ФабрикаXDTO.ЗаписатьXML(КомпонентыОбмена.ФайлОбмена, ДанныеXDTO);
			Прервать;
			
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

// Параметры:
//   КомпонентыОбмена - Структура - содержит все ключевые данные для обмена (ПКО, ПКПД, ПОД и т.д.).
//   Ссылка - удаленный объект.
//   ПравилоКонвертации  - строка таблицы правил конвертации объектов, в соответствии с которой выполняется преобразование.
//
Процедура ВыгрузитьУдаление(КомпонентыОбмена, Ссылка, ПравилоКонвертации = Неопределено)
	
	Если ПравилоКонвертации <> Неопределено Тогда
		// ПКО передали явно (при вызове удаления для конкретного ПКО).
		Если Не ОбъектФорматаПроходитПоФильтруXDTO(КомпонентыОбмена, ПравилоКонвертации.ОбъектФормата) Тогда
			Возврат;
		КонецЕсли;
		
		ЗаписатьУдалениеОбъектаXDTO(КомпонентыОбмена, Ссылка, ПравилоКонвертации.ТипСсылкиXDTO);
	Иначе
		
		// Поиск ПКО
		МассивИменПКО = ПОДПоОбъектуМетаданных(КомпонентыОбмена, Ссылка.Метаданные()).ИспользуемыеПКО;
		
		// Массив нужен для "свертки" ПКО по типам XDTO.
		ОбработанныеТипыСсылокXDTO = Новый Массив;
		
		Для Каждого ПравилоКонвертацииИмя Из МассивИменПКО Цикл
			
			ПравилоКонвертации = КомпонентыОбмена.ПравилаКонвертацииОбъектов.Найти(ПравилоКонвертацииИмя, "ИмяПКО");
			
			Если ПравилоКонвертации = Неопределено Тогда
				// Допустимо указание ПКО, не предназначенного для текущей версии формата данных.
				Продолжить;
			КонецЕсли;
			
			Если Не ОбъектФорматаПроходитПоФильтруXDTO(КомпонентыОбмена, ПравилоКонвертации.ОбъектФормата) Тогда
				Продолжить;
			КонецЕсли;
			
			// "Свертка" ПКО по типу ссылки XDTO.
			ТипСсылкиXDTO = ПравилоКонвертации.ТипСсылкиXDTO;
			Если ОбработанныеТипыСсылокXDTO.Найти(ТипСсылкиXDTO) = Неопределено Тогда
				ОбработанныеТипыСсылокXDTO.Добавить(ТипСсылкиXDTO);
			Иначе
				Продолжить;
			КонецЕсли;
			
			ЗаписатьУдалениеОбъектаXDTO(КомпонентыОбмена, Ссылка, ТипСсылкиXDTO);
			
		КонецЦикла;
		
	КонецЕсли;
КонецПроцедуры

Функция КонвертироватьПеречислениеВXDTO(КомпонентыОбмена, ЗначениеПеречисления, ТипПеречисленияXDTO)
	Если ТипЗнч(ЗначениеПеречисления) = Тип("Строка") Тогда
		
		ЗначениеПеречисленияФормата = ТранслироватьПеречисление(ЗначениеПеречисления, "ru", ТипПеречисленияXDTO);
		
		ЗначениеXDTO = ФабрикаXDTO.Создать(ТипПеречисленияXDTO, ЗначениеПеречисленияФормата);
		
	Иначе
	
		ПравилаКонвертацииПредопределенныхДанных = КомпонентыОбмена.ПравилаКонвертацииПредопределенныхДанных;
		
		ПравилоКонвертации = НайтиПравилоКонвертацииДляЗначения(
			ПравилаКонвертацииПредопределенныхДанных, ТипЗнч(ЗначениеПеречисления), ТипПеречисленияXDTO);
		
		ЗначениеXDTO = ФабрикаXDTO.Создать(ТипПеречисленияXDTO,
			ЗначениеПеречисленияXDTO(ПравилоКонвертации.КонвертацииЗначенийПриОтправке, ЗначениеПеречисления));
		
	КонецЕсли;
	Возврат ЗначениеXDTO;
КонецФункции

Функция НайтиПравилоКонвертацииДляЗначения(ПравилаКонвертацииПредопределенныхДанных, Знач Тип, Знач ТипXDTO = Неопределено)
	
	Если ТипXDTO = Неопределено Тогда
		
		НайденныеПравила = ПравилаКонвертацииПредопределенныхДанных.НайтиСтроки(Новый Структура("ТипДанных", Тип));
		
		Если НайденныеПравила.Количество() = 1 Тогда
			
			ПравилоКонвертации = НайденныеПравила[0];
			
			Возврат ПравилоКонвертации;
			
		ИначеЕсли НайденныеПравила.Количество() > 1 Тогда
			
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Ошибка правил конвертации предопределенных данных.
				|Задано более одного правила конвертации для типа источника <%1>.'"),
				Строка(Тип));
			
		КонецЕсли;
		
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Ошибка правил конвертации предопределенных данных.
			|Правило конвертации не определено для типа источника <%1>.'"),
			Строка(Тип));
			
	Иначе
		
		НайденныеПравила = ПравилаКонвертацииПредопределенныхДанных.НайтиСтроки(Новый Структура("ТипДанных, ТипXDTO", Тип, ТипXDTO, Ложь));
		
		Если НайденныеПравила.Количество() = 1 Тогда
			
			ПравилоКонвертации = НайденныеПравила[0];
			
			Возврат ПравилоКонвертации;
			
		ИначеЕсли НайденныеПравила.Количество() > 1 Тогда
			
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Ошибка правил конвертации предопределенных данных.
				|Задано более одного правила конвертации для типа источника <%1> и типа приемника <%2>.'"),
				Строка(Тип),
				Строка(ТипXDTO));
			
		КонецЕсли;
		
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Ошибка правил конвертации предопределенных данных.
			|Правило конвертации не определено для типа источника <%1> и типа приемника <%2>.'"),
			Строка(Тип),
			Строка(ТипXDTO));
		
	КонецЕсли;
	
КонецФункции

Функция ЗначениеПеречисленияXDTO(Знач КонвертацииЗначений, Знач Значение)
	
	ЗначениеXDTO = КонвертацииЗначений.Получить(Значение);
	
	Если ЗначениеXDTO = Неопределено Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не найдено правило конвертации для значения предопределенных данных.
			|Тип значения источника: <%1>
			|Значение источника: <%2>'"),
			ТипЗнч(Значение),
			Строка(Значение));
	КонецЕсли;
	
	Возврат ЗначениеXDTO;
КонецФункции

Функция КонвертироватьСсылкуВXDTO(КомпонентыОбмена, ЗначениеСсылки, ТипСсылкиXDTO)
	
	Если КомпонентыОбмена.ЭтоОбменЧерезПланОбмена Тогда
	
		УИДОбъектаXDTO = РегистрыСведений.ПубличныеИдентификаторыСинхронизируемыхОбъектов.ПубличныйИдентификаторПоСсылкеОбъекта(
			КомпонентыОбмена.УзелКорреспондента, ЗначениеСсылки);
		ЗначениеXDTO = ФабрикаXDTO.Создать(ТипСсылкиXDTO, УИДОбъектаXDTO);
			
		Возврат ЗначениеXDTO;
		
	Иначе
		Возврат СокрЛП(ЗначениеСсылки.УникальныйИдентификатор());
	КонецЕсли;
	
КонецФункции

Функция ЭтоТаблицаОбъекта(Знач СвойствоXDTO)
	
	Если ТипЗнч(СвойствоXDTO.Тип) = Тип("ТипОбъектаXDTO")
		И СвойствоXDTO.Тип.Свойства.Количество() = 1 Тогда
		
		Возврат СвойствоXDTO.Тип.Свойства[0].ВерхняяГраница <> 1;
		
	КонецЕсли;
	
	Возврат Ложь;
КонецФункции

Функция ЭтоТипТаблицыОбъекта(Знач ТипСвойстваXDTO)
	
	Если ТипЗнч(ТипСвойстваXDTO) = Тип("ТипОбъектаXDTO")
		И ТипСвойстваXDTO.Свойства.Количество() = 1 Тогда
		
		Возврат ТипСвойстваXDTO.Свойства[0].ВерхняяГраница <> 1;
		
	КонецЕсли;
	
	Возврат Ложь;
КонецФункции

Процедура ПолучитьЗначениеВложенныхСвойств(ИсточникСвойства, ВложенныеСвойства, ЗначениеСвойства)
	ТекущийИсточникСвойства = ИсточникСвойства;
	ТекущееЗначениеСвойства = Неопределено;
	Для Уровень = 0 По ВложенныеСвойства.Количество()-1 Цикл
		Если НЕ ТекущийИсточникСвойства.Свойство(ВложенныеСвойства[Уровень], ТекущееЗначениеСвойства) Тогда
			Прервать;
		КонецЕсли;
		Если Уровень = ВложенныеСвойства.Количество()-1 Тогда
			ЗначениеСвойства = ТекущееЗначениеСвойства;
		ИначеЕсли ТипЗнч(ТекущееЗначениеСвойства) <> Тип("Структура") Тогда
			Прервать;
		Иначе
			ТекущийИсточникСвойства = ТекущееЗначениеСвойства;
			ТекущееЗначениеСвойства = Неопределено;
		КонецЕсли;
	КонецЦикла;
КонецПроцедуры

Процедура ПоместитьЗначениеВложенныхСвойств(ПолучательСвойства, ВложенныеСвойства, ЗначениеСвойства, ЭтоСтрокаТЧ)
	ИмяСвойства = ВложенныеСвойства[0];
	ЗначениеВложенныхСвойств = Неопределено;
	Если ЭтоСтрокаТЧ Тогда
		Если ПолучательСвойства.Владелец().Колонки.Найти(ИмяСвойства) = Неопределено Тогда
			ПолучательСвойства.Владелец().Колонки.Добавить(ИмяСвойства);
		Иначе
			ЗначениеВложенныхСвойств = ПолучательСвойства[ИмяСвойства];
		КонецЕсли;
	Иначе
		Если НЕ ПолучательСвойства.Свойство(ИмяСвойства, ЗначениеВложенныхСвойств) Тогда
			ПолучательСвойства.Вставить(ИмяСвойства);
		КонецЕсли;
	КонецЕсли;
	Если ЗначениеВложенныхСвойств = Неопределено Тогда
		ЗначениеВложенныхСвойств = Новый Структура;
	КонецЕсли;
	СтруктураВложенныхСвойств = ЗначениеВложенныхСвойств;
	МаксимальныйУровень = ВложенныеСвойства.Количество() - 1;
	Для Уровень = 1 По МаксимальныйУровень Цикл
		ИмяВложенногоСвойства = ВложенныеСвойства[Уровень];
		Если Уровень = МаксимальныйУровень Тогда
			СтруктураВложенныхСвойств.Вставить(ИмяВложенногоСвойства, ЗначениеСвойства);
			Прервать;
		КонецЕсли;
		ПолучательВложенногоСвойства = Неопределено;
		СтруктураВложенныхСвойств.Свойство(ИмяВложенногоСвойства, ПолучательВложенногоСвойства);
		Если ПолучательВложенногоСвойства = Неопределено Тогда
			ПолучательВложенногоСвойства = Новый Структура;
		КонецЕсли;
		ПолучательВложенногоСвойства.Вставить(ИмяВложенногоСвойства, Новый Структура);
		СтруктураВложенныхСвойств = ПолучательВложенногоСвойства;
	КонецЦикла;
	ПолучательСвойства[ИмяСвойства] = ЗначениеВложенныхСвойств;
КонецПроцедуры

Функция СоздатьТЧПриемникаПоПКС(ПКСДляТЧ)
	
	НоваяТЧПриемника = Новый ТаблицаЗначений;
	Для Каждого ПКС Из ПКСДляТЧ Цикл
		ИмяКолонки = СокрЛП(ПКС.СвойствоФормата);
		// Возможно, это ПКС для вложенных свойств.
		Если СтрНайти(ИмяКолонки, ".") > 0 Тогда
			ВложенныеСвойства = СтрРазделить(ИмяКолонки,".",Ложь);
			МаксимальныйИндекс = ВложенныеСвойства.Количество() - 1;
			Для Индекс = 0 По МаксимальныйИндекс Цикл
				ИмяВложенногоСвойства = ВложенныеСвойства[Индекс];
				Если НоваяТЧПриемника.Колонки.Найти(ИмяВложенногоСвойства) = Неопределено Тогда
					НоваяТЧПриемника.Колонки.Добавить(ИмяВложенногоСвойства);
				КонецЕсли;
			КонецЦикла;
		Иначе
			НоваяТЧПриемника.Колонки.Добавить(ИмяКолонки);
		КонецЕсли;
	КонецЦикла;
	
	Если НоваяТЧПриемника.Колонки.Количество() > 0 Тогда

		НоваяТЧПриемника.Колонки.Добавить("Расширения");
		
	КонецЕсли;
	
	Возврат НоваяТЧПриемника;
	
КонецФункции

Процедура ВыгрузитьПоддерживаемыеОбъектыФормата(Header, ПоддерживаемыеОбъекты, УзелКорреспондента)
	
	ТаблицаВсеВерсии = Новый ТаблицаЗначений;
	ТаблицаВсеВерсии.Колонки.Добавить("Версия", Новый ОписаниеТипов("Строка"));
	
	Для Каждого AvailableVersion Из Header.AvailableVersion Цикл
		СтрокаТаблицаВсеВерсии = ТаблицаВсеВерсии.Добавить();
		СтрокаТаблицаВсеВерсии.Версия = AvailableVersion;
	КонецЦикла;
	
	ТаблицаВсеВерсии.Сортировать("Версия");
	
	СтрокаВсеВерсии = СтрСоединить(ТаблицаВсеВерсии.ВыгрузитьКолонку("Версия"), ",");
	
	ТаблицаПоддерживаемыеОбъекты = ПоддерживаемыеОбъекты.Скопировать();
	
	ТаблицаПоддерживаемыеОбъекты.Сортировать("Объект, Версия");
	
	ДоступныеТипыОбъектовXDTO = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(XMLБазоваяСхема(), "AvailableObjectTypes"));
	
	ТекущийОбъект = Неопределено;
	Для Каждого СтрокаПоддерживаемыеОбъекты Из ТаблицаПоддерживаемыеОбъекты Цикл
		Если ТекущийОбъект = Неопределено Тогда
			СоздатьНовыйОбъект = Истина;
		ИначеЕсли ТекущийОбъект.Name <> СтрокаПоддерживаемыеОбъекты.Объект Тогда
			
			Если ТекущийОбъект.Sending = СтрокаВсеВерсии Тогда
				ТекущийОбъект.Sending = "*";
			КонецЕсли;
			
			Если ТекущийОбъект.Receiving = СтрокаВсеВерсии Тогда
				ТекущийОбъект.Receiving = "*";
			КонецЕсли;
			
			ДоступныеТипыОбъектовXDTO.ObjectType.Добавить(ТекущийОбъект);
			СоздатьНовыйОбъект = Истина;
		Иначе
			СоздатьНовыйОбъект = Ложь;
		КонецЕсли;
		
		Если СоздатьНовыйОбъект Тогда
			ТекущийОбъект = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(XMLБазоваяСхема(), "ObjectType"));
			ТекущийОбъект.Name = СтрокаПоддерживаемыеОбъекты.Объект;
			
			ТекущийОбъект.Sending   = "";
			ТекущийОбъект.Receiving = "";
		КонецЕсли;
		
		Если СтрокаПоддерживаемыеОбъекты.Отправка Тогда
			Если ПустаяСтрока(ТекущийОбъект.Sending) Тогда
				ТекущийОбъект.Sending = СтрокаПоддерживаемыеОбъекты.Версия;
			Иначе
				ТекущийОбъект.Sending = ТекущийОбъект.Sending + "," + СтрокаПоддерживаемыеОбъекты.Версия;
			КонецЕсли;
		КонецЕсли;
		
		Если СтрокаПоддерживаемыеОбъекты.Получение Тогда
			Если ПустаяСтрока(ТекущийОбъект.Receiving) Тогда
				ТекущийОбъект.Receiving = СтрокаПоддерживаемыеОбъекты.Версия;
			Иначе
				ТекущийОбъект.Receiving = ТекущийОбъект.Receiving + "," + СтрокаПоддерживаемыеОбъекты.Версия;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Если ТекущийОбъект <> Неопределено Тогда
		Если ТекущийОбъект.Sending = СтрокаВсеВерсии Тогда
			ТекущийОбъект.Sending = "*";
		КонецЕсли;
		
		Если ТекущийОбъект.Receiving = СтрокаВсеВерсии Тогда
			ТекущийОбъект.Receiving = "*";
		КонецЕсли;
		
		ДоступныеТипыОбъектовXDTO.ObjectType.Добавить(ТекущийОбъект);
	КонецЕсли;
	
	Если ДоступныеТипыОбъектовXDTO.ObjectType.Количество() > 0 Тогда
		Header.AvailableObjectTypes = ДоступныеТипыОбъектовXDTO;
	Иначе
		Header.AvailableObjectTypes = Неопределено;
	КонецЕсли;
	
	РегистрыСведений.НастройкиОбменаДаннымиXDTO.ОбновитьНастройки(
		УзелКорреспондента, "ПоддерживаемыеОбъекты", ТаблицаПоддерживаемыеОбъекты);
	
КонецПроцедуры

// Структура параметров заголовка сообщения по умолчанию.
// 
// Возвращаемое значение:
//   Структура - описание параметров заголовка сообщения обмена:
//     * ФорматОбмена - Строка - имя формата обмена.
//     * ЭтоОбменЧерезПланОбмена - Булево - признак обмена через план обмена.
//     * ОбменДаннымиСВнешнейСистемой - Булево - признак обмена с внешней системой.
//     * ВерсияФорматаОбмена - Строка - номер версии формата обмена.
//     * ИмяПланаОбмена - Строка - имя метаданных плана обмена.
//     * ПсевдонимПредопределенногоУзла - Строка - код предопределенного узла до перекодирования.
//     * ИдентификаторПолучателя - Строка - идентификатор узла получателя сообщения.
//     * ИдентификаторОтправителя - Строка - идентификатор узла отправителя сообщения.
//     * НомерСообщения - Число - номер исходящего сообщения.
//     * НомерПринятого - Число - номер сообщения, загруженного корреспондентом.
//     * ПоддерживаемыеВерсии - Массив из Строка - коллекция поддерживаемых версий формата.
//     * ПоддерживаемыеОбъекты - ТаблицаЗначений - коллекция поддерживаемых объектов формата.
//     * Префикс - Строка - префикс информационной базы корреспондента.
//     * УзелКорреспондента - ПланОбменаСсылка
//                          - Неопределено - узел плана обмена.
//
Функция ПараметрыЗаголовкаСообщенияОбмена() Экспорт
	
	ПараметрыЗаголовка = Новый Структура;
	ПараметрыЗаголовка.Вставить("ФорматОбмена",            "");
	ПараметрыЗаголовка.Вставить("ЭтоОбменЧерезПланОбмена", Ложь);
	ПараметрыЗаголовка.Вставить("ОбменДаннымиСВнешнейСистемой", Ложь);
	ПараметрыЗаголовка.Вставить("ВерсияФорматаОбмена",     "");
	
	ПараметрыЗаголовка.Вставить("ИмяПланаОбмена",                 "");
	ПараметрыЗаголовка.Вставить("ПсевдонимПредопределенногоУзла", "");
	
	ПараметрыЗаголовка.Вставить("ИдентификаторПолучателя", "");
	ПараметрыЗаголовка.Вставить("ИдентификаторОтправителя", "");
	
	ПараметрыЗаголовка.Вставить("НомерСообщения", 0);
	ПараметрыЗаголовка.Вставить("НомерПринятого", 0);
	
	ПараметрыЗаголовка.Вставить("ПоддерживаемыеВерсии",  Новый Массив);
	ПараметрыЗаголовка.Вставить("ПоддерживаемыеОбъекты", Новый ТаблицаЗначений);
	
	ПараметрыЗаголовка.Вставить("Префикс", "");
	
	ПараметрыЗаголовка.Вставить("УзелКорреспондента", Неопределено);
	
	ПараметрыЗаголовка.Вставить("ОбменЧерезОбработкуВыгрузкаЗагрузкаED", Ложь);
	
	Возврат ПараметрыЗаголовка;
	
КонецФункции

// Параметры:
//   ФайлОбмена - ЗаписьXML - объект для записи заголовка.
//   ПараметрыЗаголовка - см. ОбменДаннымиXDTOСервер.ПараметрыЗаголовкаСообщенияОбмена
// 
Процедура ЗаписатьЗаголовокСообщенияОбмена(ФайлОбмена, ПараметрыЗаголовка) Экспорт
	
	// Записываем элемент <Message>
	ФайлОбмена.ЗаписатьНачалоЭлемента("Message");
	ФайлОбмена.ЗаписатьСоответствиеПространстваИмен("msg", "http://www.1c.ru/SSL/Exchange/Message");
	ФайлОбмена.ЗаписатьСоответствиеПространстваИмен("xs",  "http://www.w3.org/2001/XMLSchema");
	ФайлОбмена.ЗаписатьСоответствиеПространстваИмен("xsi", "http://www.w3.org/2001/XMLSchema-instance");
	
	// Элемент <Header>
	ЗаголовокСообщенияXDTO = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(XMLБазоваяСхема(), "Header"));
	
	ЗаголовокСообщенияXDTO.Format       = ПараметрыЗаголовка.ФорматОбмена;
	ЗаголовокСообщенияXDTO.CreationDate = ТекущаяУниверсальнаяДата();
	
	ДоступныеВерсииXDTO = ЗаголовокСообщенияXDTO.AvailableVersion; // СписокXDTO
	
	Если ПараметрыЗаголовка.ЭтоОбменЧерезПланОбмена Тогда
		
		ПодтверждениеXDTO = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(XMLБазоваяСхема(), "Confirmation"));
		
		Если ПараметрыЗаголовка.ОбменДаннымиСВнешнейСистемой Тогда
			ПодтверждениеXDTO.From = ПараметрыЗаголовка.ИдентификаторОтправителя;
		
			ПодтверждениеXDTO.MessageNo  = ПараметрыЗаголовка.НомерСообщения;
			ПодтверждениеXDTO.ReceivedNo = ПараметрыЗаголовка.НомерПринятого;
			
			ЗаголовокСообщенияXDTO.Confirmation = ПодтверждениеXDTO;
			
			Для Каждого ВерсияФормата Из ПараметрыЗаголовка.ПоддерживаемыеВерсии Цикл
				ДоступныеВерсииXDTO.Добавить(ВерсияФормата);
			КонецЦикла;
			
			ВыгрузитьПоддерживаемыеОбъектыФормата(ЗаголовокСообщенияXDTO,
				ПараметрыЗаголовка.ПоддерживаемыеОбъекты, ПараметрыЗаголовка.УзелКорреспондента);
		Иначе
			ИмяПланаОбмена = ТранслироватьИмя(ПараметрыЗаголовка.ИмяПланаОбмена, "ru");
			ПодтверждениеXDTO.ExchangePlan = ИмяПланаОбмена;
			ПодтверждениеXDTO.To           = ПараметрыЗаголовка.ИдентификаторПолучателя;
			
			Если ЗначениеЗаполнено(ПараметрыЗаголовка.ПсевдонимПредопределенногоУзла) Тогда
				// Требуется корректировка кода узла отправителя.
				ПодтверждениеXDTO.From = ПараметрыЗаголовка.ПсевдонимПредопределенногоУзла;
			Иначе
				ПодтверждениеXDTO.From = ПараметрыЗаголовка.ИдентификаторОтправителя;
			КонецЕсли;
		
			ПодтверждениеXDTO.MessageNo  = ПараметрыЗаголовка.НомерСообщения;
			ПодтверждениеXDTO.ReceivedNo = ПараметрыЗаголовка.НомерПринятого;
			
			ЗаголовокСообщенияXDTO.Confirmation = ПодтверждениеXDTO;
			
			Для Каждого ВерсияФормата Из ПараметрыЗаголовка.ПоддерживаемыеВерсии Цикл
				ДоступныеВерсииXDTO.Добавить(ВерсияФормата);
			КонецЦикла;
			
			Если ЗначениеЗаполнено(ПараметрыЗаголовка.ПсевдонимПредопределенногоУзла) Тогда
				// Тип Header является Упорядоченным, поэтому важен порядок присвоения значений свойств.
				// В противном случае может быть не пройдена валидация по схеме.
				ЗаголовокСообщенияXDTO.NewFrom = ПараметрыЗаголовка.ИдентификаторОтправителя;
			КонецЕсли;
			
			ВыгрузитьПоддерживаемыеОбъектыФормата(ЗаголовокСообщенияXDTO,
				ПараметрыЗаголовка.ПоддерживаемыеОбъекты, ПараметрыЗаголовка.УзелКорреспондента);
			
			ЗаголовокСообщенияXDTO.Prefix = ПараметрыЗаголовка.Префикс;
			
			Если Не ПараметрыЗаголовка.ОбменЧерезОбработкуВыгрузкаЗагрузкаED Тогда
				ОбменДаннымиКонтрольЗацикливания.ВыгрузитьКонтурВСообщение(ЗаголовокСообщенияXDTO, ПараметрыЗаголовка.ИмяПланаОбмена);
			КонецЕсли;
			
		КонецЕсли;
		
	Иначе
		ДоступныеВерсииXDTO.Добавить(ПараметрыЗаголовка.ВерсияФорматаОбмена);
	КонецЕсли;
	
	ФабрикаXDTO.ЗаписатьXML(ФайлОбмена, ЗаголовокСообщенияXDTO);
	
КонецПроцедуры

// Параметры:
//   ОбъектXDTO - ОбъектXDTO
//   ТипXDTO - ТипОбъектаXDTO
//   Контекст - Структура
//   Отказ - Булево
//   ОписаниеОшибки - Строка
//
Процедура ПроверитьОбъектXDTOПоСхеме(ОбъектXDTO, ТипXDTO, Контекст, Отказ, ОписаниеОшибки)
	
	ПодробноеПредставление        = "";
	ПользовательскоеПредставление = "";
	
	Попытка
		ОбъектXDTO.Проверить();
	Исключение
		Отказ = Истина;
		ПодробноеПредставление = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
	КонецПопытки;
	
	Если Отказ Тогда
		СтекОшибок = Новый Массив;
		ЗаполнитьОшибкиПроверкиОбъектаXDTO(ОбъектXDTO, ТипXDTO, СтекОшибок);
		
		Если СтекОшибок.Количество() > 0 Тогда
			ПользовательскоеПредставление = ТипXDTO.Имя;
			Для Каждого ТекущаяОшибка Из СтекОшибок Цикл
				ПользовательскоеПредставление = ПользовательскоеПредставление + Символы.ПС + ТекущаяОшибка;
			КонецЦикла;
		КонецЕсли;
	КонецЕсли;
	
	ОписаниеОшибки = Новый Структура("КраткоеПредставление, ПодробноеПредставление");
	
	ШаблонПользовательскоеСообщениеОбОшибке =
	НСтр("ru = 'Не удалось выполнить конвертацию в объект формата ""%1"": 
	|%2
	|
	|Дополнительная информация:
	|Направление: %3.
	|ПОД: %4.
	|ПКО: %5.
	|Объект: %6.
	|
	|Подробнее см. в журнале регистрации.'");
	
	ШаблонСообщениеОбОшибкеЖР = 
	НСтр("ru = 'Направление: %1.
	|ПОД: %2.
	|ПКО: %3.
	|Объект: %4.
	|
	|%5'");
	
	ОписаниеОшибки.КраткоеПредставление = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		ШаблонПользовательскоеСообщениеОбОшибке,
		ТипXDTO.Имя,
		ПользовательскоеПредставление,
		Контекст.НаправлениеОбмена,
		Контекст.ИмяПОД,
		Контекст.ИмяПКО,
		Контекст.ПредставлениеОбъекта);
	ОписаниеОшибки.ПодробноеПредставление = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		ШаблонСообщениеОбОшибкеЖР,
		Контекст.НаправлениеОбмена,
		Контекст.ИмяПОД,
		Контекст.ИмяПКО,
		Контекст.ПредставлениеОбъекта,
		ПодробноеПредставление);
	
КонецПроцедуры

Процедура ЗаполнитьОшибкиПроверкиОбъектаXDTO(ОбъектXDTO, ТипОбъектаXDTO, СтекОшибок, Знач Уровень = 1)
	
	ВыводитьОшибку = (Уровень = 1);
	
	Для Каждого Свойство Из ТипОбъектаXDTO.Свойства Цикл
		Если Не ОбъектXDTO.Установлено(Свойство) Тогда
			Если Свойство.НижняяГраница = 1
				И Не Свойство.ВозможноПустое Тогда
				Отступ = СтроковыеФункцииКлиентСервер.СформироватьСтрокуСимволов("  ", Уровень);
				СообщениеОбОшибке = Отступ + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = '%1: не заполнено обязательное поле.'"),
					Свойство.Имя);
				СтекОшибок.Добавить(СообщениеОбОшибке);
			КонецЕсли;
			Продолжить;
		Иначе
			ЗначениеСвойстваXDTO = Неопределено;
			ЭтоСписокXDTO = Ложь;
			Если Свойство.ВерхняяГраница = 1 Тогда
				ЗначениеСвойстваXDTO = ОбъектXDTO.ПолучитьXDTO(Свойство);
			Иначе
				ЗначениеСвойстваXDTO = ОбъектXDTO.ПолучитьСписок(Свойство);
				ЭтоСписокXDTO = Истина;
			КонецЕсли;
			
			Если ЗначениеСвойстваXDTO = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			
			Если ТипЗнч(ЗначениеСвойстваXDTO) = Тип("ЗначениеXDTO") Тогда
				Попытка
					Свойство.Тип.Проверить(ЗначениеСвойстваXDTO.ЛексическоеЗначение);
				Исключение
					Отступ = СтроковыеФункцииКлиентСервер.СформироватьСтрокуСимволов("  ", Уровень);
					СообщениеОбОшибке = Отступ + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = '%1: значение поля не соответствует заданным ограничениям.'"),
						Свойство.Имя);
					СтекОшибок.Добавить(СообщениеОбОшибке);
				КонецПопытки;
			ИначеЕсли ЭтоСписокXDTO Тогда
				Сч = 0;
				Для Каждого ЭлементСпискаXDTO Из ЗначениеСвойстваXDTO Цикл
					Сч = Сч + 1;
					НовыйСтекОшибок = Новый Массив;
					ЗаполнитьОшибкиПроверкиОбъектаXDTO(ЭлементСпискаXDTO, Свойство.Тип, НовыйСтекОшибок, Уровень + 1);
					
					Если НовыйСтекОшибок.Количество() > 0 Тогда
						Отступ = СтроковыеФункцииКлиентСервер.СформироватьСтрокуСимволов("  ", Уровень);
						СообщениеОбОшибке = Отступ + Свойство.Имя + "[" + XMLСтрока(Сч) + "]";
						СтекОшибок.Добавить(СообщениеОбОшибке);
						Для Каждого НоваяОшибка Из НовыйСтекОшибок Цикл
							СтекОшибок.Добавить(НоваяОшибка);
						КонецЦикла;
					КонецЕсли;
				КонецЦикла;
			Иначе
				НовыйСтекОшибок = Новый Массив;
				ЗаполнитьОшибкиПроверкиОбъектаXDTO(ЗначениеСвойстваXDTO, Свойство.Тип, НовыйСтекОшибок, Уровень + 1);
				
				Если НовыйСтекОшибок.Количество() > 0 Тогда
					Отступ = СтроковыеФункцииКлиентСервер.СформироватьСтрокуСимволов("  ", Уровень);
					СообщениеОбОшибке = Отступ + Свойство.Имя;
					СтекОшибок.Добавить(СообщениеОбОшибке);
					Для Каждого НоваяОшибка Из НовыйСтекОшибок Цикл
						СтекОшибок.Добавить(НоваяОшибка);
					КонецЦикла;
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

#КонецОбласти

#Область ПолучениеДанных

#Область КонвертацияОбъектов

#Область КонвертацияXDTOВСтруктуру

Процедура КонвертацияСвойстваXDTOВЭлементСтруктуры(Источник, Свойство, Приемник,
	КомпонентыОбмена, ИмяДляСвойстваСоставногоТипа = "", ТипСвойства = Неопределено)
	
	Если Не Источник.Установлено(Свойство) Тогда
		Возврат;
	КонецЕсли;
	
	ПространствоИменСвойства = Свойство.URIПространстваИмен;
	
	Если Не ПространствоИменАктивно(КомпонентыОбмена, ПространствоИменСвойства) Тогда
		Возврат;
	КонецЕсли;
	
	ИмяСвойства = ?(ИмяДляСвойстваСоставногоТипа = "", Свойство.Имя, ИмяДляСвойстваСоставногоТипа);
	
	ЗначениеXDTO = Источник.ПолучитьXDTO(Свойство);
	Если ТипСвойства <> Неопределено Тогда
		
		ТипЗначенияXDTO = ТипСвойства;
		
	ИначеЕсли ЗначениеXDTO <> Неопределено Тогда
		
		ТипЗначенияXDTO = ТипЗначенияСвойстваXDTO(КомпонентыОбмена, Свойство, ЗначениеXDTO);
		
	Иначе
		
		Возврат;
		
	КонецЕсли;
	
	Попытка
		Если ТипЗнч(ЗначениеXDTO) = Тип("ЗначениеXDTO") Тогда
			
			КонвертироватьПростоеСвойства(Приемник, ИмяСвойства, ЗначениеXDTO, ТипЗначенияXDTO);
			
		ИначеЕсли ТипЗнч(ЗначениеXDTO) = Тип("ОбъектXDTO") Тогда
			
			// В свойстве могут находиться:
			// - дополнительная информация
			// - табличная часть
			// - набор ключевых свойств
			// - набор общих свойств
			// - свойство составного типа.
			
			КлассЗначенияXDTO = ИмяКлассаЗначенияXDTO(Свойство, ТипЗначенияXDTO);
			
			Если КлассЗначенияXDTO = КлассПроизвольныеДанные() Тогда // Дополнительная информация
				
				Значение = СериализаторXDTO.ПрочитатьXDTO(ЗначениеXDTO);
				Приемник.Вставить(ИмяСвойства, Значение);
				
			ИначеЕсли КлассЗначенияXDTO = КлассТаблицаОбъекта() Тогда
				
				КонвертироватьТаблицуОбъекта(Приемник, КомпонентыОбмена, ИмяСвойства, Свойство, ТипЗначенияXDTO, ЗначениеXDTO);
				
			ИначеЕсли КлассЗначенияXDTO = КлассКлючевыеСвойстваФормата() Тогда
				
				КонвертироватьКлючевоеСвойство(Приемник, КомпонентыОбмена, ИмяСвойства, ТипЗначенияXDTO, ЗначениеXDTO);
				
			ИначеЕсли КлассЗначенияXDTO = КлассОбщиеСвойства() Тогда 
				
				КонвертироватьОбщееСвойство(Приемник, КомпонентыОбмена, ИмяСвойства, ТипЗначенияXDTO, ЗначениеXDTO);
				
			Иначе
				
				КонвертироватьСоставноеСвойство(Приемник, КомпонентыОбмена, ИмяСвойства, ТипЗначенияXDTO, ЗначениеXDTO);
				
			КонецЕсли;
		КонецЕсли;
	Исключение
		ПредставлениеОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Ошибка чтения объекта XDTO, имя свойства: <%1>.'"), ИмяСвойства)
			+ Символы.ПС + Символы.ПС + ПредставлениеОшибки;
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
КонецПроцедуры

Функция ПрочитатьЗначениеXDTO(ЗначениеXDTO, ТипСвойства = Неопределено)
	
	ТипСвойства = ?(ТипСвойства = Неопределено, ЗначениеXDTO.Тип(), ТипСвойства);
	
	Если ЗначениеXDTO = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Если ЭтоСсылкаXDTO(ТипСвойства) Тогда // Конвертация ссылки
		
		Значение = ПрочитатьЗначениеXDTOСложногоТипа(ЗначениеXDTO, "Ссылка", ТипСвойства);
		
	ИначеЕсли ЗначениеXDTO.Тип().Фасеты <> Неопределено
		И ЗначениеXDTO.Тип().Фасеты.Перечисления <> Неопределено
		И ЗначениеXDTO.Тип().Фасеты.Перечисления.Количество() > 0 Тогда // Конвертация перечисления
		
		Значение = ПрочитатьЗначениеXDTOСложногоТипа(ЗначениеXDTO, "Перечисление", ТипСвойства);
		
	Иначе // Конвертация обычного значения.
		
		Значение = ЗначениеXDTO.Значение;
		
	КонецЕсли;
	
	Возврат Значение;
	
КонецФункции

Функция ПрочитатьЗначениеXDTOСложногоТипа(ЗначениеXDTO, СложныйТип, ТипСвойства = Неопределено)

	ТипСвойства = ?(ТипСвойства = Неопределено, ЗначениеXDTO.Тип(), ТипСвойства);
		
	СтруктураXDTO = Новый Структура;
	СтруктураXDTO.Вставить("ЭтоСсылка", СложныйТип = "Ссылка");
	СтруктураXDTO.Вставить("ЭтоПеречисление", СложныйТип = "Перечисление");
	СтруктураXDTO.Вставить("ТипЗначенияXDTO", ТипСвойства);
		
	Если СложныйТип = "Перечисление" Тогда
		Значение = ТранслироватьИмя(ЗначениеXDTO.Значение, "en");
		СтруктураXDTO.Вставить("Значение", Значение);
	Иначе
		СтруктураXDTO.Вставить("Значение", ЗначениеXDTO.Значение);
	КонецЕсли;
	
	Возврат СтруктураXDTO;
	
КонецФункции

// Параметры:
//   Таблица - ТаблицаЗначений - таблица для инициализации колонок.
//   Тип - ТипОбъектаXDTO - тип объекта.
//
Процедура ИнициализироватьКолонкиТаблицыОбъектаПоТипу(Таблица, Знач Тип)
	
	Для Каждого Колонка Из Тип.Свойства Цикл
		Если СтрНайти(Колонка.Тип.Имя, КлассОбщиеСвойства()) > 0 Тогда
			ИнициализироватьКолонкиТаблицыОбъектаПоТипу(Таблица, Колонка.Тип);
		Иначе
			Таблица.Колонки.Добавить(Колонка.Имя);
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

// Определение типа свойства XDTO.
//
// Если свойство относится к базовому пакету XDTO, то тип можно получить прямым обращением методом Тип().
// Если переданное свойство принадлежит расширению пакета XDTO, то обращении метод Тип() возвращает AnyType,
// т.е. тип определен не будет.
//
// Для получения типа свойства из расширения необходимо:
//  1. Получить имя базового объекта (объекта, который расширяем);
//  2. По имени базового объекта получить объект из расширения;
//  3. У объекта из п2 выбрать свойство с нужным именем и зачитать его тип.
//
// Возвращаемое значение:
//  ТипЗначенияXDTO - тип свойства объекта XDTO.
//
Функция ТипЗначенияСвойстваXDTO(Знач КомпонентыОбмена, Знач СвойствоXDTO, ЗначениеXDTO)
	
	Результат = ЗначениеXDTO.Тип();
	Если СвойствоXDTO.ОбъектВладелец = Неопределено Тогда
		
		// Владельца может не быть у полностью нового объекта, который добавляется расширением
		// Например, работаем со справочником, который отсутствует в типовой конфигурации.
		Возврат Результат;
		
	КонецЕсли;
	
	ПространствоИменСвойства = СвойствоXDTO.URIПространстваИмен;
	Если ЭтоБазоваяСхема(КомпонентыОбмена, ПространствоИменСвойства) Тогда
		
		Возврат Результат;
		
	КонецЕсли;
	
	ТипXDTOВладельцаСвойства = СвойствоXDTO.ОбъектВладелец.Тип();
	
	ПространствоИменВладельца = ТипXDTOВладельцаСвойства.URIПространстваИмен;
	Если НЕ ЭтоБазоваяСхема(КомпонентыОбмена, ПространствоИменВладельца) Тогда
		
		// Свойство должно принадлежать объекту XDTO базовой схемы
		Возврат Результат;
		
	КонецЕсли;
	
	ОбъектXDTOРасширения = ФабрикаXDTO.Тип(ПространствоИменСвойства, ТипXDTOВладельцаСвойства.Имя);
	Если ОбъектXDTOРасширения <> Неопределено Тогда
		
		СвойствоОбъектаXDTOРасширения = ОбъектXDTOРасширения.Свойства.Получить(СвойствоXDTO.Имя);
		Если СвойствоОбъектаXDTOРасширения <> Неопределено Тогда
			
			Результат = СвойствоОбъектаXDTOРасширения.Тип;
			
		КонецЕсли;
		

	КонецЕсли;
	
	Возврат Результат;	
	
КонецФункции

// Определение класса для значения свойства.
// Класс используется для выбора алгоритма преобразования в структуру.
//
Функция ИмяКлассаЗначенияXDTO(Знач СвойствоXDTO, Знач ТипЗначенияXDTO)
	
	Если СвойствоXDTO.Имя = "AdditionalInfo" Тогда
		Возврат КлассПроизвольныеДанные();
	ИначеЕсли ЭтоТипТаблицыОбъекта(ТипЗначенияXDTO) Тогда
		Возврат КлассТаблицаОбъекта();
	ИначеЕсли СтрНайти(ТипЗначенияXDTO.Имя, КлассКлючевыеСвойства()) > 0 Тогда
		Возврат КлассКлючевыеСвойства();
	ИначеЕсли СтрНайти(ТипЗначенияXDTO.Имя, КлассКлючевыеСвойстваФормата()) > 0 Тогда
		Возврат КлассКлючевыеСвойстваФормата();
	ИначеЕсли СтрНайти(ТипЗначенияXDTO.Имя, КлассОбщиеСвойства()) > 0 Тогда
		Возврат КлассОбщиеСвойства();
	КонецЕсли;
	
	Возврат КлассСоставныеСвойства();
	
КонецФункции

// Инкапсуляция алгоритмов преобразования свойств объекта XDTO в элементы структуры
//
Процедура КонвертироватьПростоеСвойства(Приемник,Знач ИмяСвойства, Знач ЗначениеXDTO, Знач ТипСвойства)
	
	Значение = ПрочитатьЗначениеXDTO(ЗначениеXDTO, ТипСвойства);
	
	Если ТипЗнч(Приемник) = Тип("Структура") Тогда
		Приемник.Вставить(ИмяСвойства, Значение);
	Иначе
		
		Если ТипЗнч(Приемник) = Тип("СтрокаТаблицыЗначений")
			И Приемник.Владелец().Колонки.Найти(ИмяСвойства) = Неопределено Тогда
			Возврат;
		КонецЕсли;
		
		Приемник[ИмяСвойства] = Значение;
	КонецЕсли;
	
КонецПроцедуры

Процедура КонвертироватьТаблицуОбъекта(Приемник, Знач КомпонентыОбмена, Знач ИмяСвойства, Знач СвойствоXDTO, Знач ТипЗначенияXDTO, Знач ЗначениеXDTO)
	
	// Инициализируем таблицу значений, которая отображает табличную часть объекта.
	Значение = Новый ТаблицаЗначений;
	ИнициализироватьКолонкиТаблицыОбъектаПоТипу(Значение, ТипЗначенияXDTO.Свойства[0].Тип);
	
	// Дополним таблицу свойствами активных расширений
	Если ЭтоБазоваяСхема(КомпонентыОбмена, СвойствоXDTO.URIПространстваИмен) Тогда
		
		РасширитьСвойстваТаблицыОбъекта(Значение, СвойствоXDTO.ТипВладелец.Имя, ИмяСвойства, КомпонентыОбмена.РасширенияФормата);
		
	КонецЕсли;
	
	ТабличнаяЧастьXDTO = ЗначениеXDTO.Строка;
	Если ТипЗнч(ТабличнаяЧастьXDTO) <> Тип("СписокXDTO") Тогда
		
		МассивОбъектовXDTO = Новый Массив(1);
		МассивОбъектовXDTO[0] = ТабличнаяЧастьXDTO;
		
		ТабличнаяЧастьXDTO = МассивОбъектовXDTO;
		
	КонецЕсли;
	
	СтрокаТипЗначенияXDTO = ТипЗначенияXDTO.Свойства[0].Тип;
	Для Каждого СтрокаXDTO Из ТабличнаяЧастьXDTO Цикл
		
		СтрокаТЧ = Значение.Добавить();
		Для Каждого СвойствоСтрокиТЧ Из СтрокаXDTO.Свойства() Цикл
			
			СтрокаТипСвойства = Неопределено;
			
			ЭтоБазоваяСхема = ЭтоБазоваяСхема(КомпонентыОбмена, СвойствоСтрокиТЧ.URIПространстваИмен);
			Если ЭтоБазоваяСхема Тогда
				
				СтрокаТипСвойства = СвойствоСтрокиТЧ.Тип;
				
			Иначе
				
				СтрокаТипСвойства = ТипВложенногоСвойстваПоИмениИзРасширенияФормата(КомпонентыОбмена, СтрокаТипЗначенияXDTO.Имя, СвойствоСтрокиТЧ.Имя);
				
			КонецЕсли;
			
			КонвертацияСвойстваXDTOВЭлементСтруктуры(СтрокаXDTO, СвойствоСтрокиТЧ, СтрокаТЧ, КомпонентыОбмена, , СтрокаТипСвойства);
			
		КонецЦикла;
		
	КонецЦикла;
	
	Приемник.Вставить(ИмяСвойства, Значение);
	
КонецПроцедуры

Процедура КонвертироватьОбщееСвойство(Приемник, Знач КомпонентыОбмена, Знач ИмяСвойства, Знач ТипЗначенияXDTO, Знач ЗначениеXDTO)

	Если ТипЗнч(Приемник) = Тип("Структура") Тогда 
		ПриемникГруппыСвойств = Новый Структура;
		Для Каждого ПодСвойство Из ЗначениеXDTO.Свойства() Цикл
			
			ОписаниеСвойства = ТипЗначенияXDTO.Свойства.Получить(ПодСвойство.Имя);
			Если ОписаниеСвойства = Неопределено Тогда
				
				// Если общего свойства нет в базовом формате,
				// то надо проверить его в расширениях
				ПроверитьНаличиеОбщегоСвойстваВРасширениях(КомпонентыОбмена, ПодСвойство, ТипЗначенияXDTO, ОписаниеСвойства);
				Если ОписаниеСвойства = Неопределено Тогда
					
					Продолжить;
					
				КонецЕсли;
				
			КонецЕсли;
			
			КонвертацияСвойстваXDTOВЭлементСтруктуры(ЗначениеXDTO, ПодСвойство, ПриемникГруппыСвойств, КомпонентыОбмена,,ОписаниеСвойства.Тип);
			
		КонецЦикла;
		
		Приемник.Вставить(ИмяСвойства, ПриемникГруппыСвойств);
		
		// По возможности свойства из группы свойств надо продублировать в приемнике,
		// Для совместимости с существующими правилами и алгоритмами.
		ЕстьКлючевыеСвойства = Приемник.Свойство(КлассКлючевыеСвойства());
		Для Каждого СвойствоГруппы Из ПриемникГруппыСвойств Цикл
			ИмяПодСвойства = СвойствоГруппы.Ключ;
			Если НЕ Приемник.Свойство(ИмяПодСвойства)
				И НЕ (ЕстьКлючевыеСвойства И Приемник[КлассКлючевыеСвойства()].Свойство(ИмяПодСвойства)) Тогда
				Приемник.Вставить(ИмяПодСвойства, СвойствоГруппы.Значение);
			КонецЕсли;
		КонецЦикла;
		
	Иначе
		
		Для Каждого ПодСвойство Из ЗначениеXDTO.Свойства() Цикл
			
			ОписаниеСвойства = ТипЗначенияXDTO.Свойства.Получить(ПодСвойство.Имя);
			Если ОписаниеСвойства = Неопределено Тогда
				
				// Если общего свойства нет в базовом формате,
				// то надо проверить его в расширениях
				ПроверитьНаличиеОбщегоСвойстваВРасширениях(КомпонентыОбмена, ПодСвойство, ТипЗначенияXDTO, ОписаниеСвойства);
				Если ОписаниеСвойства = Неопределено Тогда
					
					Продолжить;
					
				КонецЕсли;
				
			КонецЕсли;
			
			КонвертацияСвойстваXDTOВЭлементСтруктуры(ЗначениеXDTO, ПодСвойство, Приемник, КомпонентыОбмена,,ОписаниеСвойства.Тип);
			
		КонецЦикла;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура КонвертироватьКлючевоеСвойство(Приемник, Знач КомпонентыОбмена, Знач ИмяСвойства, Знач ТипЗначенияXDTO, Знач ЗначениеXDTO)
	
	Значение = Новый Структура("ЭтоНаборКлючевыхСвойств");
	Значение.Вставить("ТипЗначения", СтрЗаменить(ТипЗначенияXDTO.Имя, КлассКлючевыеСвойстваФормата(), ""));

	Для Каждого КлючевоеСвойство Из ЗначениеXDTO.Свойства() Цикл
		ОписаниеСвойства = ТипЗначенияXDTO.Свойства.Получить(КлючевоеСвойство.Имя);
		Если ОписаниеСвойства = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		КонвертацияСвойстваXDTOВЭлементСтруктуры(ЗначениеXDTO, КлючевоеСвойство, Значение, КомпонентыОбмена,,ОписаниеСвойства.Тип);
	КонецЦикла;
	
	ДополнитьТаблицуСвойствамиАктивныхРасширений(КомпонентыОбмена, ТипЗначенияXDTO, ЗначениеXDTO, Значение);
	
	Если ТипЗнч(Приемник) = Тип("Структура") Тогда
		Приемник.Вставить(ИмяСвойства, Значение);
	Иначе
		Приемник[ИмяСвойства] = Значение;
	КонецЕсли;

КонецПроцедуры

Процедура КонвертироватьСоставноеСвойство(Приемник, Знач КомпонентыОбмена, Знач ИмяСвойства, Знач ТипЗначенияXDTO, Знач ЗначениеXDTO)

	Значение = Неопределено;
	Для Каждого ПодСвойство Из ЗначениеXDTO.Свойства() Цикл
		
		ОписаниеСвойства = ТипЗначенияXDTO.Свойства.Получить(ПодСвойство.Имя);
		Если ОписаниеСвойства = Неопределено Тогда
			Продолжить;
		КонецЕсли;

		Если НЕ ЗначениеXDTO.Установлено(ПодСвойство) Тогда
			Продолжить;
		КонецЕсли;
		
		КонвертацияСвойстваXDTOВЭлементСтруктуры(ЗначениеXDTO, ПодСвойство, Приемник, КомпонентыОбмена, ИмяСвойства, ОписаниеСвойства.Тип);
		Прервать;
		
	КонецЦикла;

КонецПроцедуры

// Формализация классов значения свойств
//
Функция КлассОбщиеСвойства()
	
	Возврат "ОбщиеСвойства"; // @Non-NLS
	
КонецФункции

Функция КлассСоставныеСвойства()
	
	Возврат "СоставныеСвойства"; // @Non-NLS
	
КонецФункции

Функция КлассПроизвольныеДанные()
	
	Возврат "ПроизвольныеДанные"; // @Non-NLS
	
КонецФункции

Функция КлассТаблицаОбъекта()
	
	Возврат "ТаблицаОбъекта"; // @Non-NLS
	
КонецФункции

Функция КлассСсылка()

	Возврат "Ссылка";
	
КонецФункции

Функция КлассСсылкаФормата()

	Возврат "Ссылка"; // @Non-NLS
	
КонецФункции

#КонецОбласти

#Область КонвертацияСтруктурыВДанныеИБ

Процедура КонвертацияСвойствСтруктурыОбъектаXDTO(
		КомпонентыОбмена,
		ДанныеXDTO,
		ПолученныеДанные,
		ПравилоКонвертации,
		НомерЭтапа = 1,
		СоставСвойств = "Все")
	
	Попытка
		Для Каждого ПКС Из ПравилоКонвертации.Свойства Цикл
			
			Если СоставСвойств = "СвойстваПоиска"
				И Не ПКС.ОбработкаПоисковогоСвойства Тогда
				Продолжить;
			КонецЕсли;
			
			КонвертацияСвойстваСтруктурыОбъектаXDTO(
				КомпонентыОбмена,
				ДанныеXDTO,
				ПолученныеДанные.ДополнительныеСвойства,
				ПолученныеДанные,
				ПКС,
				НомерЭтапа);
			
		КонецЦикла;
			
		Если СоставСвойств = "СвойстваПоиска" Тогда
			Возврат;
		КонецЕсли;
		
		// Конвертация табличных частей.
		Для Каждого ТЧ Из ПравилоКонвертации.СвойстваТабличныхЧастей Цикл
			
			Если НомерЭтапа = 1 И ЗначениеЗаполнено(ТЧ.ТЧКонфигурации) И ЗначениеЗаполнено(ТЧ.ТЧФормата) Тогда
				
				// Прямая конвертация табличных частей.
				ТЧФормата = Неопределено; // ТаблицаЗначений
				Если НЕ ДанныеXDTO.Свойство(ТЧ.ТЧФормата, ТЧФормата) Тогда
					Продолжить;
				ИначеЕсли ТЧФормата.Количество() = 0 Тогда
					Продолжить;
				КонецЕсли;
				
				МассивКолонокТЧ = Новый Массив;
				Для Каждого КолонкаТЧ Из ТЧФормата.Колонки Цикл
					МассивКолонокТЧ.Добавить(КолонкаТЧ.Имя);
				КонецЦикла;
				
				ИменаКолонокСтрокой = СтрСоединить(МассивКолонокТЧ, ",");
				Для НомерСтроки = 1 По ТЧФормата.Количество() Цикл
					
					ДанныеСтрокиXDTO = ТЧФормата[НомерСтроки - 1];
					СтрокаТЧ = ПолученныеДанные[ТЧ.ТЧКонфигурации].Добавить();
					СтруктураДанныхСтрокиXDTO = Новый Структура(ИменаКолонокСтрокой);
					ЗаполнитьЗначенияСвойств(СтруктураДанныхСтрокиXDTO, ДанныеСтрокиXDTO);
					
					Для Каждого ПКС Из ТЧ.Свойства Цикл
						Если ПКС.ИспользуетсяАлгоритмКонвертации Тогда
							Продолжить;
						КонецЕсли;
						КонвертацияСвойстваСтруктурыОбъектаXDTO(
							КомпонентыОбмена,
							СтруктураДанныхСтрокиXDTO,
							ПолученныеДанные.ДополнительныеСвойства,
							СтрокаТЧ,
							ПКС,
							НомерЭтапа);
					КонецЦикла;
					
				КонецЦикла;
				
			КонецЕсли;
			
			Если НомерЭтапа = 2 И ТЧ.ИспользуетсяАлгоритмКонвертации
				И ЗначениеЗаполнено(ТЧ.ТЧКонфигурации)
				И ПолученныеДанные.ДополнительныеСвойства.Свойство(ТЧ.ТЧКонфигурации) Тогда
 				МассивСтруктурСДаннымиСтрок = ПолученныеДанные.ДополнительныеСвойства[ТЧ.ТЧКонфигурации];
				КоличествоСтрокТЧКонфигурации = ПолученныеДанные[ТЧ.ТЧКонфигурации].Количество();
				
				Для НомерСтроки = 1 По МассивСтруктурСДаннымиСтрок.Количество() Цикл
					
					// Возможно, строка уже была добавлена при прямой конвертации
					Если НомерСтроки <= КоличествоСтрокТЧКонфигурации Тогда
						СтрокаТЧ = ПолученныеДанные[ТЧ.ТЧКонфигурации][НомерСтроки - 1];
					Иначе
						СтрокаТЧ = ПолученныеДанные[ТЧ.ТЧКонфигурации].Добавить();
					КонецЕсли;
					
					Для Каждого ПКС Из ТЧ.Свойства Цикл
						
						Если НЕ ПКС.ИспользуетсяАлгоритмКонвертации Тогда
							Продолжить;
						КонецЕсли;
						
						КонвертацияСвойстваСтруктурыОбъектаXDTO(
							КомпонентыОбмена,
							ДанныеXDTO,
							ПолученныеДанные.ДополнительныеСвойства,
							СтрокаТЧ,
							ПКС,
							НомерЭтапа, 
							ТЧ.ТЧКонфигурации);
						
					КонецЦикла;
					
				КонецЦикла;
			КонецЕсли;
			
		КонецЦикла;
	Исключение
		ТекстОшибки = Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Событие: %1.
				|Объект: %2.
				|
				|Ошибка конвертации свойств.
				|%3.'"),
			КомпонентыОбмена.НаправлениеОбмена,
			ПредставлениеОбъектаДляПротокола(ПолученныеДанные),
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
КонецПроцедуры

Процедура КонвертацияСвойстваСтруктурыОбъектаXDTO(
		КомпонентыОбмена,
		ДанныеXDTO,
		ДополнительныеСвойства,
		ПриемникДанных,
		ПКС,
		НомерЭтапа = 1,
		ИмяТЧ = "")
	// Обрабатывается ПКС где указано только свойство формата - оно используется только при выгрузке.
	Если СокрЛП(ПКС.СвойствоКонфигурации) = "" Тогда
		Возврат;
	КонецЕсли;
	
	ПравилоКонвертацииСвойства = ПКС.ПравилоКонвертацииСвойства;
	
	ЗначениеСвойства = "";
	Попытка
		Если НомерЭтапа = 1 Тогда
			
			Если Не ЗначениеЗаполнено(ПКС.СвойствоФормата) Тогда
				Возврат;
			КонецЕсли;
			
			Если ПКС.ОбработкаКлючевогоСвойства
				И Не ДанныеXDTO.Свойство("ЭтоНаборКлючевыхСвойств") Тогда
				ИсточникДанных = ДанныеXDTO[КлассКлючевыеСвойства()];
			Иначе
				ИсточникДанных = ДанныеXDTO;
			КонецЕсли;
			
			СвойствоФормата_Имя = СокрЛП(ПКС.СвойствоФормата);
			ПозицияТочки = СтрНайти(СвойствоФормата_Имя, ".");
			// Указано полное имя свойства, входящего в группу общих свойств.
			Если ПозицияТочки > 0 Тогда
				ВложенныеСвойства = СтрРазделить(СвойствоФормата_Имя,".",Ложь);
				ПолучитьЗначениеВложенныхСвойств(ИсточникДанных, ВложенныеСвойства, ЗначениеСвойства);
			Иначе
				
				Если НЕ ИсточникДанных.Свойство(СвойствоФормата_Имя, ЗначениеСвойства)
					И НЕ ПКС.ОбработкаКлючевогоСвойства 
					И НЕ ПКС.ИспользуетсяАлгоритмКонвертации
					Тогда
					
					Если ПриемникДанных.ДополнительныеСвойства.Свойство("СвойстваОтсутствующиеВПолученныхДанных") Тогда
						
						ПриемникДанных.ДополнительныеСвойства.СвойстваОтсутствующиеВПолученныхДанных = ПриемникДанных.ДополнительныеСвойства.СвойстваОтсутствующиеВПолученныхДанных + "," + СвойствоФормата_Имя;
						
					Иначе
						
						ПриемникДанных.ДополнительныеСвойства.Вставить("СвойстваОтсутствующиеВПолученныхДанных", СвойствоФормата_Имя);
						
					КонецЕсли;
					
				КонецЕсли;
				
			КонецЕсли;
			
		ИначеЕсли НомерЭтапа = 2 Тогда
			
			Если НомерЭтапа = 2 И Не ПКС.ИспользуетсяАлгоритмКонвертации Тогда
				Возврат;
			КонецЕсли;
			
			// На 2-м этапе значения свойств получаются из дополнительных свойств объекта полученных данных
			// и представляют из себя структуру, содержащую инструкцию для конвертации, либо значение XDTO.
			// Если приемником значения является строка табличной части, то значение свойства располагается
			// в ДополнительныеСвойства[ИмяТабличнойЧасти][ИндексСтроки].
			Если ЗначениеЗаполнено(ИмяТЧ) Тогда
				ИсточникДанных = ДополнительныеСвойства[ИмяТЧ][ПриемникДанных.НомерСтроки - 1];
			Иначе
				ИсточникДанных = ДополнительныеСвойства;
			КонецЕсли;
			
			Если ИсточникДанных.Свойство(ПКС.СвойствоКонфигурации) Тогда
				ЗначениеСвойства = ИсточникДанных[ПКС.СвойствоКонфигурации];
			КонецЕсли;
			
		КонецЕсли;
		
		Если Не ЗначениеЗаполнено(ЗначениеСвойства) Тогда
			Возврат;
		КонецЕсли;
		
		УдалятьСозданныеПоКлючевымСвойствам = КомпонентыОбмена.УдалятьСозданныеПоКлючевымСвойствам;
		Если ТипЗнч(ЗначениеСвойства) = Тип("Структура")
			И ЗначениеСвойства.Свойство("ИмяПКО")
			И ЗначениеСвойства.Свойство("Значение") Тогда
			
			// Значением является инструкция.
			Если ЗначениеСвойства.Свойство("УдалятьСозданныеПоКлючевымСвойствам") Тогда
				УдалятьСозданныеПоКлючевымСвойствам = ЗначениеСвойства.УдалятьСозданныеПоКлючевымСвойствам;
			КонецЕсли;
			
			ПравилоКонвертацииСвойства = ЗначениеСвойства.ИмяПКО;
			ЗначениеСвойства           = ЗначениеСвойства.Значение;
			
		КонецЕсли;
		
		Если ТипЗнч(ЗначениеСвойства) = Тип("Структура") Тогда
			Если Не ЗначениеЗаполнено(ПравилоКонвертацииСвойства) Тогда
				Возврат;
			КонецЕсли;
			
			ПКПД = КомпонентыОбмена.ПравилаКонвертацииПредопределенныхДанных.Найти(ПравилоКонвертацииСвойства, "ИмяПКПД");
			Если ПКПД <> Неопределено Тогда
				
				Значение = ПКПД.КонвертацииЗначенийПриПолучении.Получить(ЗначениеСвойства.Значение);
				ПриемникДанных[ПКС.СвойствоКонфигурации] = Значение;
				Возврат;
				
			Иначе
				ПравилоКонвертацииСвойства = ПКОПоИмени(КомпонентыОбмена, ПравилоКонвертацииСвойства);
			КонецЕсли;
		Иначе
			// Конвертацию простых свойств выполняем только на 1-м этапе.
			ПриемникДанных[ПКС.СвойствоКонфигурации] = ЗначениеСвойства;
			Возврат;
		КонецЕсли;
		
		ПравилоКонвертации = Новый Структура("ПравилоКонвертации, УдалятьСозданныеПоКлючевымСвойствам",
			ПравилоКонвертацииСвойства, УдалятьСозданныеПоКлючевымСвойствам);
		ДанныеДляЗаписиВИБ = СтруктураОбъектаXDTOВДанныеИБ(КомпонентыОбмена, ЗначениеСвойства, ПравилоКонвертации, "ПолучитьСсылку");
		
		Если ДанныеДляЗаписиВИБ <> Неопределено Тогда
			ПриемникДанных[ПКС.СвойствоКонфигурации] = ДанныеДляЗаписиВИБ.Ссылка;
		КонецЕсли;
		
	Исключение
		ПредставлениеОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Ошибка конвертации свойства объекта XDTO, имя свойства: <%1>.'"), ПКС.СвойствоКонфигурации)
			+ Символы.ПС + Символы.ПС + ПредставлениеОшибки;
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
КонецПроцедуры

Функция СсылкаОбъектаПоСвойствамОбъектаXDTO(ПравилоКонвертации, ПолученныеДанные, ДанныеXDTOСодержатСсылку, КомпонентыОбмена, ОригинальныйУИДСтрокой = "")

	УзелОбмена = КомпонентыОбмена.УзелКорреспондента;
	
	Результат = Неопределено;
	// ПравилоКонвертации.ПоляПоискаОбъекта - массив, содержит разные варианты поиска
	//	элементы массива - таблица значений с полями поиска.
	Если ПравилоКонвертации.ПоляПоиска = Неопределено
		ИЛИ ТипЗнч(ПравилоКонвертации.ПоляПоиска) <> Тип("Массив") Тогда
		Возврат Результат;
	КонецЕсли;
	
	Для Каждого ПопыткаПоиска Из ПравилоКонвертации.ПоляПоиска Цикл
		ПоляПоиска = Новый Структура(ПопыткаПоиска);
		ЗаполнитьЗначенияСвойств(ПоляПоиска, ПолученныеДанные);
		
		// Если хотя бы одно поле поиска не заполнено, вариант поиска пропускается.
		// (Кроме справочников и планов видов характеристик - для них допустимо
		// незаполненное поле поиска "Родитель").
		// Вариант поиска является полноценным, если заполнены все поля.
		// В противном случае должен сработать другой вариант поиска.
		ЕстьНезаполненныеПоля = Ложь;
		Для Каждого ПолеПоиска Из ПоляПоиска Цикл
			Если Не ЗначениеЗаполнено(ПолеПоиска.Значение) Тогда
				Если (ПравилоКонвертации.ЭтоСправочник Или ПравилоКонвертации.ЭтоПланВидовХарактеристик)
					И ПолеПоиска.Ключ = "Родитель" Тогда
					Продолжить;
				КонецЕсли;
				
				ЕстьНезаполненныеПоля = Истина;
				Прервать;
			КонецЕсли;
		КонецЦикла;
		Если ЕстьНезаполненныеПоля Тогда
			// Переход к следующему варианту поиска.
			Продолжить;
		КонецЕсли;
		
		ВариантИдентификации = СокрЛП(ПравилоКонвертации.ВариантИдентификации);
		АнализироватьПубличныеИдентификаторы = ВариантИдентификации = "СначалаПоУникальномуИдентификаторуПотомПоПолямПоиска"
			И ДанныеXDTOСодержатСсылку
			И ЗначениеЗаполнено(УзелОбмена);
			
		ПоискЗапросом = Ложь;
		Если АнализироватьПубличныеИдентификаторы Тогда
			ПоискЗапросом = Истина;
		Иначе
			// Возможно, поиск можно выполнить платформенными методами.
			Если ПравилоКонвертации.ЭтоДокумент
				И ПоляПоиска.Количество() = 2
				И ПоляПоиска.Свойство("Дата")
				И ПоляПоиска.Свойство("Номер") Тогда
				Результат = ПравилоКонвертации.МенеджерОбъекта.НайтиПоНомеру(ПоляПоиска.Номер, ПоляПоиска.Дата);
				Результат = ?(Результат.Пустая(), Неопределено, Результат);
			ИначеЕсли ПравилоКонвертации.ЭтоСправочник
				И ПоляПоиска.Количество() = 1
				И ПоляПоиска.Свойство("Наименование") Тогда
				Результат = ПравилоКонвертации.МенеджерОбъекта.НайтиПоНаименованию(ПоляПоиска.Наименование, Истина);
			ИначеЕсли ПравилоКонвертации.ЭтоСправочник
				И ПоляПоиска.Количество() = 1
				И ПоляПоиска.Свойство("Код") Тогда
				Результат = ПравилоКонвертации.МенеджерОбъекта.НайтиПоКоду(ПоляПоиска.Код);
			Иначе
				ПоискЗапросом = Истина;
			КонецЕсли;
		КонецЕсли;
		
		Если ПоискЗапросом Тогда
			Запрос = Новый Запрос;
			
			ТекстЗапроса =
			"ВЫБРАТЬ
			|	Таблица.Ссылка КАК Ссылка
			|ИЗ
			|	&ПолноеИмя КАК Таблица
			|ГДЕ
			|	&УсловиеОтбора";
			
			Отбор = Новый Массив;
			
			Для Каждого ПолеПоиска Из ПоляПоиска Цикл
				
				Если ОбменДаннымиПовтИсп.ЭтоСтроковыйРеквизитНеограниченнойДлины(ПравилоКонвертации.ПолноеИмя, ПолеПоиска.Ключ) Тогда
					
					ОтборСтрокой = "ВЫРАЗИТЬ(Таблица.[Ключ] КАК СТРОКА([ДлинаСтроки])) = &[Ключ]";
					ОтборСтрокой = СтрЗаменить(ОтборСтрокой, "[Ключ]", ПолеПоиска.Ключ);
					ОтборСтрокой = СтрЗаменить(ОтборСтрокой, "[ДлинаСтроки]", Формат(СтрДлина(ПолеПоиска.Значение), "ЧГ=0"));
					Отбор.Добавить(ОтборСтрокой);
					
				Иначе
					
					Отбор.Добавить(СтрЗаменить("Таблица.[Ключ] = &[Ключ]", "[Ключ]", ПолеПоиска.Ключ));
					
				КонецЕсли;
				
				Запрос.УстановитьПараметр(ПолеПоиска.Ключ, ПолеПоиска.Значение);
				
			КонецЦикла;
			
			УсловиеОтбора = СтрСоединить(Отбор, " И ");
			
			ИспользоватьКешПубличныхИдентификаторов = КомпонентыОбмена.ИспользоватьКешПубличныхИдентификаторов;
			Если АнализироватьПубличныеИдентификаторы И Не ИспользоватьКешПубличныхИдентификаторов Тогда
				
				// Из поиска необходимо исключить уже сопоставленные ранее объекты.
				Если НЕ ПустаяСтрока(ОригинальныйУИДСтрокой) Тогда
					
					ТекстСоединения = "	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПубличныеИдентификаторыСинхронизируемыхОбъектов КАК ПубличныеИдентификаторы
					|	ПО ПубличныеИдентификаторы.Ссылка = Таблица.Ссылка 
					|		И ПубличныеИдентификаторы.УзелИнформационнойБазы = &УзелОбмена 
					|		И ПубличныеИдентификаторы.Идентификатор <> &ОригинальныйУИДСтрокой";
					
					Запрос.УстановитьПараметр("ОригинальныйУИДСтрокой", ОригинальныйУИДСтрокой);
					
				Иначе
					
					ТекстСоединения = "	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПубличныеИдентификаторыСинхронизируемыхОбъектов КАК ПубличныеИдентификаторы
						|	ПО ПубличныеИдентификаторы.Ссылка = Таблица.Ссылка 
						|		И ПубличныеИдентификаторы.УзелИнформационнойБазы = &УзелОбмена";
					
				КонецЕсли;
				
				УсловиеОтбора = УсловиеОтбора + Символы.ПС + "	И ПубличныеИдентификаторы.Ссылка is null";
				ТекстЗапроса = СтрЗаменить(ТекстЗапроса,  "ГДЕ", ТекстСоединения + Символы.ПС + "	ГДЕ");
				Запрос.УстановитьПараметр("УзелОбмена", УзелОбмена);
				
			КонецЕсли;
			
			ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&УсловиеОтбора", УсловиеОтбора);
			ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ПолноеИмя", ПравилоКонвертации.ПолноеИмя);
			Запрос.Текст = ТекстЗапроса;
			
			РезультатЗапроса = Запрос.Выполнить();
			
			Если Не РезультатЗапроса.Пустой() Тогда
				
				Выборка = РезультатЗапроса.Выбрать();
				Выборка.Следующий();
								
				Если ИспользоватьКешПубличныхИдентификаторов Тогда
					СтруктураЗаписи = Новый Структура("Ссылка", Выборка.Ссылка);
					
					Если АнализироватьПубличныеИдентификаторы 
						И ЗаписьЕстьВКешеПубличныхИдентификаторов(СтруктураЗаписи, КомпонентыОбмена) Тогда
						Продолжить;
					КонецЕсли;
				КонецЕсли;
				
				Результат = Выборка.Ссылка;
				
			КонецЕсли;
			
		КонецЕсли;
		Если ЗначениеЗаполнено(Результат) Тогда
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Процедура ЗаполнитьДанныеИБПоПолученнымДанным(ДанныеИБ, ПолученныеДанные, ПравилоКонвертации)
	
	СвойстваОтсутствующиеВПолученныхДанных = Новый Массив;
	Если ПолученныеДанные.ДополнительныеСвойства.Свойство("СвойстваОтсутствующиеВПолученныхДанных") Тогда
		
		СвойстваОтсутствующиеВПолученныхДанных = СтрРазделить(ПолученныеДанные.ДополнительныеСвойства.СвойстваОтсутствующиеВПолученныхДанных, ",", Ложь);
		
	КонецЕсли;
	
	ПоляКопии = ПравилоКонвертации.Свойства.ВыгрузитьКолонку("СвойствоКонфигурации");
	Если ПоляКопии.Количество() > 0 Тогда
		
		Для НомерПоля = 0 По ПоляКопии.ВГраница() Цикл
			
			ПоляКопии[НомерПоля] = СокрЛП(ПоляКопии[НомерПоля]);
			
		КонецЦикла;
		
		Для НомерОтсутствующегоПоля = 0 По СвойстваОтсутствующиеВПолученныхДанных.ВГраница() Цикл
			
			СвойстваОтсутствующиеВПолученныхДанных[НомерОтсутствующегоПоля] = СокрЛП(СвойстваОтсутствующиеВПолученныхДанных[НомерОтсутствующегоПоля]);
			
			ИндексОтсутствующегоПоля = ПоляКопии.Найти(СвойстваОтсутствующиеВПолученныхДанных[НомерОтсутствующегоПоля]);
			Если ИндексОтсутствующегоПоля <> Неопределено Тогда
				
				ПоляКопии.Удалить(ИндексОтсутствующегоПоля);
				
			КонецЕсли;
			
		КонецЦикла;
		
		ПоляКопируемые = СтрСоединить(ПоляКопии, ",");
		ПоляИсключаемые = СтрСоединить(СвойстваОтсутствующиеВПолученныхДанных, ",");
		
		ЗаполнитьЗначенияСвойств(ДанныеИБ, ПолученныеДанные, ПоляКопируемые, ПоляИсключаемые);
		
	КонецЕсли;
	
	Для Каждого КонвертацииТЧ Из ПравилоКонвертации.СвойстваТабличныхЧастей Цикл
		
		ИмяТЧ = КонвертацииТЧ.ТЧКонфигурации;
		
		Если ПустаяСтрока(ИмяТЧ) Тогда
			Продолжить;
		КонецЕсли;
		
		ДанныеИБ[ИмяТЧ].Очистить();
		ДанныеИБ[ИмяТЧ].Загрузить(ПолученныеДанные[ИмяТЧ].Выгрузить());
		
	КонецЦикла;
	
КонецПроцедуры

Функция ИнициализироватьПолученныеДанные(ПравилоКонвертации)
	
	ПолученныеДанные = Неопределено;
	
	Если ПравилоКонвертации.ЭтоДокумент Тогда
		ПолученныеДанные = ПравилоКонвертации.МенеджерОбъекта.СоздатьДокумент();
	ИначеЕсли ПравилоКонвертации.ЭтоСправочник
		Или ПравилоКонвертации.ЭтоПланВидовХарактеристик Тогда
		МенеджерОбъекта = ПравилоКонвертации.МенеджерОбъекта; //СправочникМенеджер
		Если ПравилоКонвертации.ПравилоДляГруппыСправочника Тогда
			ПолученныеДанные = МенеджерОбъекта.СоздатьГруппу();
		Иначе
			ПолученныеДанные = МенеджерОбъекта.СоздатьЭлемент();
		КонецЕсли;
	ИначеЕсли ПравилоКонвертации.ЭтоРегистр Тогда
		ПолученныеДанные = ПравилоКонвертации.МенеджерОбъекта.СоздатьНаборЗаписей();
	ИначеЕсли ПравилоКонвертации.ЭтоБизнесПроцесс Тогда
		ПолученныеДанные = ПравилоКонвертации.МенеджерОбъекта.СоздатьБизнесПроцесс();
	ИначеЕсли ПравилоКонвертации.ЭтоЗадача Тогда
		ПолученныеДанные = ПравилоКонвертации.МенеджерОбъекта.СоздатьЗадачу();
	ИначеЕсли ПравилоКонвертации.ЭтоПланСчетов Тогда
		ПолученныеДанные = ПравилоКонвертации.МенеджерОбъекта.СоздатьСчет();
	ИначеЕсли ПравилоКонвертации.ЭтоПланВидовРасчета Тогда
		ПолученныеДанные = ПравилоКонвертации.МенеджерОбъекта.СоздатьВидРасчета();
	КонецЕсли;
	
	Возврат ПолученныеДанные;
	
КонецФункции

#КонецОбласти

#КонецОбласти

#Область СервисныеПроцедурыИФункции

Процедура ПровестиГенерациюКодаНомераПриНеобходимости(Объект)
	
	ИмяТипаОбъекта = ОбщегоНазначения.ВидОбъектаПоТипу(ТипЗнч(Объект.Ссылка));
	
	// По типу документа смотрим заполнен код или номер.
	Если ИмяТипаОбъекта = "Документ"
		Или ИмяТипаОбъекта = "БизнесПроцесс"
		Или ИмяТипаОбъекта = "Задача" Тогда
		
		Если Не ЗначениеЗаполнено(Объект.Номер) Тогда
			
			Объект.УстановитьНовыйНомер();
			
		КонецЕсли;
		
	ИначеЕсли ИмяТипаОбъекта = "Справочник"
		Или ИмяТипаОбъекта = "ПланВидовХарактеристик" Тогда
		
		Если Не ЗначениеЗаполнено(Объект.Код)
			И Объект.Метаданные().Автонумерация Тогда
			
			Объект.УстановитьНовыйКод();
			
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура СнятьПометкуУдаленияСПредопределенногоЭлемента(Объект, ТипОбъекта, КомпонентыОбмена)
	
	ПометкаПредопределенный = Новый Структура("ПометкаУдаления, Предопределенный", Ложь, Ложь);
	ЗаполнитьЗначенияСвойств(ПометкаПредопределенный, Объект);
	
	Если ПометкаПредопределенный.ПометкаУдаления
		И ПометкаПредопределенный.Предопределенный Тогда
			
		Объект.ПометкаУдаления = Ложь;
		
		// фиксируем событие в ЖР
		ЗП            = ЗаписьПротоколаОбмена(80);
		ЗП.ТипОбъекта = ТипОбъекта;
		ЗП.Объект     = Строка(Объект);
		
		КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена =
			Перечисления.РезультатыВыполненияОбмена.ВыполненоСПредупреждениями;
		ЗаписатьВПротоколВыполнения(КомпонентыОбмена, 80, ЗП, Ложь);
		
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область ОтложенныеОперации
// Параметры:
//   ДанныеДляЗаписиВИБ - СправочникОбъект
//                      - ДокументОбъект - объект для записи.
//   ПравилоКонвертации - СтрокаТаблицыЗначений - строка с правилом конвертации.
//   КомпонентыОбмена - см. ОбменДаннымиXDTOСервер.ИнициализироватьКомпонентыОбмена
//
Процедура ЗапомнитьОбъектДляОтложенногоЗаполнения(ДанныеДляЗаписиВИБ, ПравилоКонвертации, КомпонентыОбмена)
	
	Если ПравилоКонвертации.ЕстьОбработчикПослеЗагрузкиВсехДанных Тогда
		
		// Занесем данные об объекте в таблицу отложенной обработки.
		НоваяСтрока = КомпонентыОбмена.ЗагруженныеОбъекты.Добавить();
		НоваяСтрока.ИмяОбработчика = ПравилоКонвертации.ПослеЗагрузкиВсехДанных;
		НоваяСтрока.Объект         = ДанныеДляЗаписиВИБ;
		НоваяСтрока.СсылкаНаОбъект = ДанныеДляЗаписиВИБ.Ссылка;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура УдалитьВременныеОбъектыСозданныеПоСсылкам(КомпонентыОбмена) Экспорт
	
	ТаблицаОбъектовСозданныхПоСсылкам = КомпонентыОбмена.ТаблицаОбъектовСозданныхПоСсылкам;
	
	СтрокиОбъектыДляУдаления = ТаблицаОбъектовСозданныхПоСсылкам.НайтиСтроки(Новый Структура("УдалятьСозданныеПоКлючевымСвойствам", Истина));
	
	Для Каждого СтрокаТаблицы Из СтрокиОбъектыДляУдаления Цикл
		
		СсылкаНаОбъект = СтрокаТаблицы.СсылкаНаОбъект;
		
		// Необходимо удалить ссылку на объект из таблицы для отложенного заполнения объектов.
		СтрокаТаблицыОтложенногоЗаполнения = КомпонентыОбмена.ЗагруженныеОбъекты.Найти(СсылкаНаОбъект, "СсылкаНаОбъект");
		Если СтрокаТаблицыОтложенногоЗаполнения <> Неопределено Тогда
			КомпонентыОбмена.ЗагруженныеОбъекты.Удалить(СтрокаТаблицыОтложенногоЗаполнения);
		КонецЕсли;
		
		Если ЗначениеЗаполнено(СсылкаНаОбъект) Тогда
			
			ОбъектСозданныйПоСсылке = СсылкаНаОбъект.ПолучитьОбъект();
			Если ОбъектСозданныйПоСсылке <> Неопределено Тогда
				
				ОбменДаннымиСервер.УстановитьОбменДаннымиЗагрузка(ОбъектСозданныйПоСсылке, Истина, Ложь, КомпонентыОбмена.УзелКорреспондента);
				УдалитьОбъект(ОбъектСозданныйПоСсылке, Истина, КомпонентыОбмена);
				
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЦикла;
	
	ТаблицаОбъектовСозданныхПоСсылкам.Очистить();
	
КонецПроцедуры

Процедура ОтложенноеЗаполнениеОбъектов(КомпонентыОбмена)
	
	ПараметрыКонвертации = КомпонентыОбмена.ПараметрыКонвертации;
	ЗагруженныеОбъекты   = КомпонентыОбмена.ЗагруженныеОбъекты;
	
	Попытка
		
		ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
		
		КомпонентыОбмена.МенеджерОбмена.ПередОтложеннымЗаполнением(КомпонентыОбмена);
		
		ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
			ВремяНачала, "ПередОтложеннымЗаполнением", "",КомпонентыОбмена,
			ОбменДаннымиОценкаПроизводительности.ТипСобытияПравило());
		
	Исключение
		
		ШаблонОписанияОшибки = НСтр("ru = 'Направление: %1.
			|Обработчик: %2.
			|
			|Ошибка выполнения обработчика.
			|%3.'");
		
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,
			КомпонентыОбмена.НаправлениеОбмена,
			"ПередОтложеннымЗаполнением",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		
		ВызватьИсключение ТекстОшибки;
		
	КонецПопытки;
	
	Для Каждого СтрокаТаблицы Из ЗагруженныеОбъекты Цикл
		
		Если СтрокаТаблицы.Объект.ЭтоНовый() Тогда
			Продолжить;
		КонецЕсли;
		
		ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
		
		СтроковоеПредставлениеОбъекта = ПредставлениеОбъектаДляПротокола(СтрокаТаблицы.Объект.Ссылка);
		
		НачатьТранзакцию();
		Попытка
		    Блокировка = Новый БлокировкаДанных;
		    ЭлементБлокировки = Блокировка.Добавить(ОбщегоНазначения.ИмяТаблицыПоСсылке(СтрокаТаблицы.Объект.Ссылка));
		    ЭлементБлокировки.УстановитьЗначение("Ссылка", СтрокаТаблицы.Объект.Ссылка);
		    Блокировка.Заблокировать();
		    
			Объект = СтрокаТаблицы.Объект.Ссылка.ПолучитьОбъект();
			
			// Перенос дополнительных свойств.
			Для Каждого Свойство Из СтрокаТаблицы.Объект.ДополнительныеСвойства Цикл
				Объект.ДополнительныеСвойства.Вставить(Свойство.Ключ, Свойство.Значение);
			КонецЦикла;
			
			СтруктураПараметров = Новый Структура;
			СтруктураПараметров.Вставить("Объект",              Объект);
			СтруктураПараметров.Вставить("КомпонентыОбмена",    КомпонентыОбмена);
			СтруктураПараметров.Вставить("ОбъектМодифицирован", Истина);
			
			КомпонентыОбмена.МенеджерОбмена.ВыполнитьПроцедуруМодуляМенеджера(СтрокаТаблицы.ИмяОбработчика, СтруктураПараметров);
			
			Если СтруктураПараметров.ОбъектМодифицирован Тогда
				ОбменДаннымиСервер.УстановитьОбменДаннымиЗагрузка(Объект, Истина, Ложь, КомпонентыОбмена.УзелКорреспондента);
				Объект.ДополнительныеСвойства.Вставить("ПропуститьЗаписьВерсииОбъекта");
				
				Объект.Записать();
				
			КонецЕсли;

		    ЗафиксироватьТранзакцию();
		Исключение
		    ОтменитьТранзакцию();
			
			ШаблонОписанияОшибки = НСтр("ru = 'Событие: %1.
				|Обработчик: %2.
				|Объект: %3.
				|
				|Ошибка выполнения обработчика.
				|%4.'");
			
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,
				КомпонентыОбмена.НаправлениеОбмена,
				"ОтложенноеЗаполнениеОбъектов",
				СтроковоеПредставлениеОбъекта,
				ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())); 
			
			ВызватьИсключение ТекстОшибки;
		КонецПопытки;
		
		Событие = "ОтложенноеЗаполнениеОбъектов." + СтрокаТаблицы.Объект.Метаданные().ПолноеИмя();
			ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
			ВремяНачала, Событие, Объект, КомпонентыОбмена,
			ОбменДаннымиОценкаПроизводительности.ТипСобытияПравило());
		
	КонецЦикла;

КонецПроцедуры

#КонецОбласти

#Область Прочее

Функция ПространствоИменАктивно(Знач КомпонентыОбмена, Знач ПространствоИмен)
	
	Возврат ЭтоБазоваяСхема(КомпонентыОбмена, ПространствоИмен)
		Или КомпонентыОбмена.РасширенияФормата.Получить(ПространствоИмен) <> Неопределено;
	
КонецФункции

Процедура ВключитьПространствоИмен(КомпонентыОбмена, Знач ПространствоИмен, Знач Псевдоним = "") Экспорт
	
	Если ПустаяСтрока(ПространствоИмен) Тогда
		Возврат;
	КонецЕсли;
	
	КомпонентыОбмена.РасширенияФормата.Вставить(ПространствоИмен, Псевдоним);
	
КонецПроцедуры

Функция ЭтоБазоваяСхема(Знач КомпонентыОбмена, Знач ПространствоИмен)
	
	Возврат ПустаяСтрока(ПространствоИмен) 
		Или КомпонентыОбмена.БазовыеСхемыФормата.Получить(ПространствоИмен) <> Неопределено;
		
КонецФункции

Функция ДанныеРасширения(ДанныеXDTO, Знач ПространствоИмен, Знач СоздатьОбластьДанных = Истина)
	
	Если ПустаяСтрока(ПространствоИмен) Тогда
		Возврат ДанныеXDTO;
	КонецЕсли;
	
	Если Не ДанныеXDTO.Свойство("Расширения") Тогда
		Если Не СоздатьОбластьДанных Тогда
			Возврат Неопределено;
		КонецЕсли;
			
		ДанныеXDTO.Вставить("Расширения", Новый Соответствие);
	КонецЕсли;
	
	ДанныеXDTOРасширения = ДанныеXDTO.Расширения.Получить(ПространствоИмен);
	Если ДанныеXDTOРасширения = Неопределено Тогда
		ДанныеXDTO.Расширения.Вставить(ПространствоИмен, Новый Структура);
		
		ДанныеXDTOРасширения = ДанныеXDTO.Расширения.Получить(ПространствоИмен);
	КонецЕсли;
	
	Возврат ДанныеXDTOРасширения;
	
КонецФункции

Процедура ОбъявитьПространстваИмен(ФайлОбмена, Знач КомпонентыОбмена)
	
	ФайлОбмена.ЗаписатьСоответствиеПространстваИмен("", КомпонентыОбмена.XMLСхема);
	
	Счетчик = 1;
	ИспользованныеПсевдонимы = Новый Структура;
	Для Каждого ПространствоИмен Из КомпонентыОбмена.РасширенияФормата Цикл
		Если ПустаяСтрока(ПространствоИмен.Значение) 
			Или ИспользованныеПсевдонимы.Свойство(ПространствоИмен.Значение) Тогда
			
			ПространствоИмен.Значение = СтрЗаменить("ex%1", "%1", XMLСтрока(Счетчик));
			
			Счетчик = Счетчик + 1;
		КонецЕсли;
			
		ФайлОбмена.ЗаписатьСоответствиеПространстваИмен(ПространствоИмен.Значение, ПространствоИмен.Ключ);
		
		ИспользованныеПсевдонимы.Вставить(ПространствоИмен.Значение);
	КонецЦикла;
	
КонецПроцедуры

Процедура КолонкаТаблицыПоПолюИзРасширения(ТаблицаОбъекта, ИмяКолонки)
	
	Если ТаблицаОбъекта.Колонки.Найти(ИмяКолонки) <> Неопределено Тогда
		
		Возврат;
		
	КонецЕсли;
	
	ТаблицаОбъекта.Колонки.Добавить(ИмяКолонки);
	
КонецПроцедуры

Процедура РасширитьСвойстваТаблицыОбъекта(ТаблицаОбъекта, Знач ИмяОбъекта, Знач ИмяТаблицыОбъекта, Знач РасширенияФормата)
	
	Если РасширенияФормата.Количество() < 1 Тогда
		
		Возврат;
		
	КонецЕсли;
	
	ШаблонСтрокиРасширения = "%1.%2.Строка";
	Для Каждого Расширение Из РасширенияФормата Цикл
		
		ТипТабличнаяЧастьСтрока = ФабрикаXDTO.Тип(Расширение.Ключ, СтрШаблон(ШаблонСтрокиРасширения, ИмяОбъекта, ИмяТаблицыОбъекта));
		Если ТипТабличнаяЧастьСтрока = Неопределено Тогда
			
			Продолжить;
			
		КонецЕсли;
		
		Для Каждого ПолеИзРасширения Из ТипТабличнаяЧастьСтрока.Свойства Цикл
		
			Если СтрНайти(ПолеИзРасширения.Тип.Имя, КлассОбщиеСвойства()) > 0 Тогда
				
				Для Каждого ПодчиненноеПолеИзРасширения Из ПолеИзРасширения.Тип.Свойства Цикл
					
					КолонкаТаблицыПоПолюИзРасширения(ТаблицаОбъекта, ПодчиненноеПолеИзРасширения.Имя);
					
				КонецЦикла;
				
			Иначе
				
				КолонкаТаблицыПоПолюИзРасширения(ТаблицаОбъекта, ПолеИзРасширения.Имя);
				
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЦикла;
	
КонецПроцедуры

Процедура ПрочитатьСообщениеОбмена(КомпонентыОбмена, Результаты, ТаблицыДляЗагрузки = Неопределено, РежимАнализа = Ложь)
	
	Попытка
		КомпонентыОбмена.МенеджерОбмена.ПередКонвертацией(КомпонентыОбмена);
	Исключение
		
		ШаблонОписанияОшибки = НСтр("ru = 'Направление: %1.
			|Обработчик: %2.
			|
			|Ошибка выполнения обработчика.
			|%3.'");
		
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,
			КомпонентыОбмена.НаправлениеОбмена,
			"ПередКонвертацией",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		
		ВызватьИсключение ТекстОшибки;
		
	КонецПопытки;
		
	МассивОбъектовКУдалению   = Новый Массив;
	МассивЗагруженныхОбъектов = Новый Массив;
		
	Результаты = Новый Структура;	
	Результаты.Вставить("МассивОбъектовКУдалению",   МассивОбъектовКУдалению);
	Результаты.Вставить("МассивЗагруженныхОбъектов", МассивЗагруженныхОбъектов);
	
	ВзвестиФлагОшибки = Ложь;
		
	Пока КомпонентыОбмена.ФайлОбмена.ТипУзла = ТипУзлаXML.НачалоЭлемента Цикл
		
		ОбновитьСчетчикЗагруженныхОбъектов(КомпонентыОбмена);
		
		ТипОбъектаXDTO = ФабрикаXDTO.Тип(КомпонентыОбмена.ФайлОбмена.URIПространстваИмен, КомпонентыОбмена.ФайлОбмена.ЛокальноеИмя);
		ОбъектXDTO     = ФабрикаXDTO.ПрочитатьXML(КомпонентыОбмена.ФайлОбмена, ТипОбъектаXDTO); // Объект зачитываем всегда.
		
		Если ТипОбъектаXDTO = Неопределено Тогда
			
			// Если не смогли получить тип объекта по пространству имен,
			// то переходим к чтению след порции данных xml.
			// Такое может произойти, если объект был выгружен в URI,
			// который отсутствует в приемнике, например, 
			// объект в источнике добавлен расширением, 
			// а в приемнике есть одноименный объект в рамках базового пакета XDTO.
			Продолжить;
			
		ИначеЕсли ТипОбъектаXDTO.Имя = "УдалениеОбъекта" Тогда
			
			// Загрузка признака удаления объекта - специфичная логика.
			ПрочитатьУдаление(КомпонентыОбмена, ОбъектXDTO, МассивОбъектовКУдалению, ТаблицыДляЗагрузки);
			Продолжить;
			
		КонецЕсли;
		
		// Отработка ПОД
		ПравилоОбработки = ПОДПоТипуОбъектаXDTO(КомпонентыОбмена, ТипОбъектаXDTO.Имя, Истина);
		
		Если Не ЗначениеЗаполнено(ПравилоОбработки) Тогда
			Продолжить;
		КонецЕсли;
		
		ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
		
		// Конвертируем ОбъектXDTO в Структуру.
		ДанныеXDTO = ОбъектXDTOВСтруктуру(ОбъектXDTO, КомпонентыОбмена);
		
		ИспользованиеПКО = Новый Структура;
		Для Каждого ИмяПКО Из ПравилоОбработки.ИспользуемыеПКО Цикл
			ИспользованиеПКО.Вставить(ИмяПКО, Истина);
		КонецЦикла;
		
		Событие = "ОбъектXDTOВСтруктуру." + ОбъектXDTO.Тип().Имя;
		ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
			ВремяНачала,Событие, ДанныеXDTO, КомпонентыОбмена,
			ОбменДаннымиОценкаПроизводительности.ТипСобытияБиблиотека());
		
		ПрерватьОбработку = Ложь;
		
		ПриОбработкеПОД(
			КомпонентыОбмена,
			ПравилоОбработки,
			ДанныеXDTO,
			ИспользованиеПКО,
			ПрерватьОбработку);
		
		Если ПрерватьОбработку Тогда
			ВзвестиФлагОшибки = Истина;
			Продолжить;
		КонецЕсли;
		
		Для Каждого ТекущееПКО Из ИспользованиеПКО Цикл
			Попытка
				ПравилоКонвертации = ПКОПоИмени(КомпонентыОбмена, ТекущееПКО.Ключ);
			Исключение
				ВзвестиФлагОшибки   = Истина;
				
				ОписаниеОшибки = ОписаниеОшибкиПОД(
					КомпонентыОбмена.НаправлениеОбмена,
					ПравилоОбработки.Имя,
					ПредставлениеОбъектаXDTOДляПротокола(ТипОбъектаXDTO),
					ИнформацияОбОшибке());
					
				ЗафиксироватьПроблемуПриОбработкеОбъекта(КомпонентыОбмена,
					ДанныеXDTO,
					Перечисления.ТипыПроблемОбменаДанными.ОшибкаВыполненияКодаОбработчиковПриПолученииДанных,
					ОписаниеОшибки.ПодробноеПредставление,
					ОписаниеОшибки.КраткоеПредставление);
					
				Продолжить;
			КонецПопытки;
			
			Если Не ОбъектФорматаПроходитПоФильтруXDTO(КомпонентыОбмена, ПравилоКонвертации.ОбъектФормата) Тогда
				Продолжить;
			КонецЕсли;
			
			Если Не ОбъектПроходитПоФильтруТаблицДляЗагрузки(
					ТаблицыДляЗагрузки, ТипОбъектаXDTO.Имя, ПравилоКонвертации.ТипПолученныхДанныхСтрокой) Тогда
				Продолжить;
			КонецЕсли;
			
			СинхронизироватьПоИдентификатору = ПоискПоИдентификатору(ПравилоКонвертации.ВариантИдентификации)
				И ДанныеXDTO.Свойство(КлассСсылка());
				
			Если Не ТекущееПКО.Значение Тогда
				Если СинхронизироватьПоИдентификатору Тогда
					ДополнитьСписокОбъектовКУдалению(КомпонентыОбмена,
						ПравилоКонвертации.ТипДанных, ДанныеXDTO[КлассСсылка()].Значение, МассивОбъектовКУдалению);
				КонецЕсли;
				Продолжить;
			КонецЕсли;
			
			Если РежимАнализа Тогда
				ДобавитьОбъектВТаблицуДанныхЗаголовкаПакета(КомпонентыОбмена,
					ПравилоКонвертации, ТипОбъектаXDTO.Имя, СинхронизироватьПоИдентификатору);
				
				Если СинхронизироватьПоИдентификатору Тогда
					МассивЗагруженныхОбъектов.Добавить(
						СсылкаОбъектаПоУИДОбъектаXDTO(ДанныеXDTO[КлассСсылка()].Значение, ПравилоКонвертации.ТипДанных, КомпонентыОбмена));
				КонецЕсли;
			Иначе
				Если КомпонентыОбмена.РежимЗагрузкиДанныхВИнформационнуюБазу
					Или ТаблицыДляЗагрузки <> Неопределено Тогда
					
					ДанныеДляЗаписиВИБ = Неопределено;
					Попытка
						ДанныеДляЗаписиВИБ = СтруктураОбъектаXDTOВДанныеИБ(
							КомпонентыОбмена,
							ДанныеXDTO,
							ПравилоКонвертации,
							?(КомпонентыОбмена.РежимЗагрузкиДанныхВИнформационнуюБазу, "КонвертироватьИЗаписать", "Конвертировать"));
					Исключение
						ВзвестиФлагОшибки  = Истина;
						
						ОписаниеОшибки = ОписаниеОшибкиПКО(
							КомпонентыОбмена.НаправлениеОбмена,
							ПравилоОбработки.Имя,
							ПравилоКонвертации.ИмяПКО,
							ПредставлениеОбъектаXDTOДляПротокола(ТипОбъектаXDTO),
							ИнформацияОбОшибке());
							
						ЗафиксироватьПроблемуПриОбработкеОбъекта(КомпонентыОбмена,
							ДанныеXDTO,
							Перечисления.ТипыПроблемОбменаДанными.ОшибкаВыполненияКодаОбработчиковПриПолученииДанных,
							ОписаниеОшибки.ПодробноеПредставление,
							ОписаниеОшибки.КраткоеПредставление);
							
						Продолжить;
					КонецПопытки;
						
				КонецЕсли;
				
				Если ДанныеДляЗаписиВИБ = Неопределено Тогда
					Продолжить;
				КонецЕсли;
				
				Если КомпонентыОбмена.РежимЗагрузкиДанныхВИнформационнуюБазу Тогда
					
					Если ПоискПоИдентификатору(ПравилоКонвертации.ВариантИдентификации) Тогда
						МассивЗагруженныхОбъектов.Добавить(ДанныеДляЗаписиВИБ.Ссылка);
					КонецЕсли;
					
				ИначеЕсли ТаблицыДляЗагрузки <> Неопределено Тогда
					
					ПровестиГенерациюКодаНомераПриНеобходимости(ДанныеДляЗаписиВИБ);
					
					КлючТаблицыДанных = ОбменДаннымиСервер.КлючТаблицыДанных(
						ТипОбъектаXDTO.Имя, ПравилоКонвертации.ТипПолученныхДанныхСтрокой, Ложь);
					ТаблицаДанныхСообщенияОбмена = КомпонентыОбмена.ТаблицыДанныхСообщенияОбмена.Получить(КлючТаблицыДанных); // ТаблицаЗначений
					
					УникальныйИдентификаторСтрокой = "";
					СтрокаТаблицы = Неопределено;
					Если ДанныеXDTO.Свойство(КлассСсылка()) Тогда
						УникальныйИдентификаторСтрокой = ДанныеXDTO[КлассСсылка()].Значение;
						СтрокаТаблицы = ТаблицаДанныхСообщенияОбмена.Найти(УникальныйИдентификаторСтрокой, "УникальныйИдентификатор");
					КонецЕсли;
					
					Если СтрокаТаблицы = Неопределено Тогда
						СтрокаТаблицы = ТаблицаДанныхСообщенияОбмена.Добавить();
						
						СтрокаТаблицы.ТипСтрокой              = ПравилоКонвертации.ТипПолученныхДанныхСтрокой;
						СтрокаТаблицы.УникальныйИдентификатор = УникальныйИдентификаторСтрокой;
					КонецЕсли;
					
					// Заполняем значения свойств объекта.
					ЗаполнитьЗначенияСвойств(СтрокаТаблицы, ДанныеДляЗаписиВИБ);
					
					СсылкаНаОбъект = Неопределено;
					Если СинхронизироватьПоИдентификатору Тогда
						СсылкаНаОбъект = СсылкаОбъектаПоУИДОбъектаXDTO(ДанныеXDTO[КлассСсылка()].Значение,
							ПравилоКонвертации.ТипДанных, КомпонентыОбмена);
					Иначе
						СсылкаНаОбъект = Неопределено;
					КонецЕсли;
					СтрокаТаблицы["Ссылка"] = СсылкаНаОбъект;
					
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	Если ВзвестиФлагОшибки Тогда
		КомпонентыОбмена.ФлагОшибки = Истина;
		КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка;
	КонецЕсли;
	
КонецПроцедуры

Процедура ДобавитьОбъектВТаблицуДанныхЗаголовкаПакета(КомпонентыОбмена,
		ПравилоКонвертации, ТипОбъектаXDTO, СинхронизироватьПоИдентификатору)
	
	СтрокаТаблицы = КомпонентыОбмена.ТаблицаДанныхЗаголовкаПакета.Добавить();
					
	СтрокаТаблицы.ТипОбъектаСтрокой = ПравилоКонвертации.ТипПолученныхДанныхСтрокой;
	СтрокаТаблицы.КоличествоОбъектовВИсточнике = 1;
	
	СтрокаТаблицы.ТипПриемникаСтрокой = ПравилоКонвертации.ТипПолученныхДанныхСтрокой;
	СтрокаТаблицы.ТипИсточникаСтрокой = ТипОбъектаXDTO;
	
	СтрокаТаблицы.ПоляПоиска  = ПравилоКонвертации.ПоляПредставленияОбъекта;
	СтрокаТаблицы.ПоляТаблицы = СтрСоединить(ПравилоКонвертации.РеквизитыШапкиПолученныхДанных, ",");
	
	СтрокаТаблицы.СинхронизироватьПоИдентификатору = СинхронизироватьПоИдентификатору;
		
	СтрокаТаблицы.ИспользоватьПредварительныйПросмотр = СтрокаТаблицы.СинхронизироватьПоИдентификатору;
	СтрокаТаблицы.ЭтоКлассификатор                    = ПравилоКонвертации.ВариантИдентификации = "СначалаПоУникальномуИдентификаторуПотомПоПолямПоиска";
	СтрокаТаблицы.ЭтоУдалениеОбъекта = Ложь;
	
КонецПроцедуры

Функция СоответствиеСтарыхИНовыхДанныхТЧ(ТабличнаяЧастьОбъектаПослеОбработки, ТабличнаяЧастьОбъектаДоОбработки, МассивКлючевыхПолей)
	
	СоответствиеСтрокНовойТЧСтрокамСтаройТЧ = Новый Соответствие;
	
	Для Каждого СтрокаНовойТЧ Из ТабличнаяЧастьОбъектаПослеОбработки Цикл
		
		НайденнаяСтрокаСтаройТЧ = Неопределено;
		
		СтруктураПоиска = Новый Структура;
		Для Каждого КлючевоеПоле Из МассивКлючевыхПолей Цикл
			СтруктураПоиска.Вставить(КлючевоеПоле, СтрокаНовойТЧ[КлючевоеПоле]);
		КонецЦикла;
		
		НайденныеСтрокиНовойТЧ = ТабличнаяЧастьОбъектаПослеОбработки.НайтиСтроки(СтруктураПоиска);
		
		Если НайденныеСтрокиНовойТЧ.Количество() = 1 Тогда
			
			НайденныеСтрокиСтаройТЧ = ТабличнаяЧастьОбъектаДоОбработки.НайтиСтроки(СтруктураПоиска);
			
			Если НайденныеСтрокиСтаройТЧ.Количество() = 1 Тогда
				НайденнаяСтрокаСтаройТЧ = НайденныеСтрокиСтаройТЧ[0];
			КонецЕсли;
			
		КонецЕсли;
		
		СоответствиеСтрокНовойТЧСтрокамСтаройТЧ.Вставить(СтрокаНовойТЧ, НайденнаяСтрокаСтаройТЧ);
		
	КонецЦикла;
	
	Возврат СоответствиеСтрокНовойТЧСтрокамСтаройТЧ;
	
КонецФункции

Функция РазложитьФорматОбмена(Знач ФорматОбмена)
	
	Результат = Новый Структура("БазовыйФормат, Версия");
	
	ЭлементыФормата = СтрРазделить(ФорматОбмена, "/");
	
	Если ЭлементыФормата.Количество() = 0 Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Неканоническое имя формата обмена <%1>'"), ФорматОбмена);
	КонецЕсли;
	
	Результат.Версия = ЭлементыФормата[ЭлементыФормата.ВГраница()];
	
	ПроверитьВерсию(Результат.Версия);
	
	ЭлементыФормата.Удалить(ЭлементыФормата.ВГраница());
	
	Результат.БазовыйФормат = СтрСоединить(ЭлементыФормата, "/");
	
	Возврат Результат;
КонецФункции

Функция СсылкаПоУИД(ТипЗначенияОбъектаИБ, УИДОбъектаXDTO, КомпонентыОбмена)
	
	УзелОбмена = КомпонентыОбмена.УзелКорреспондента;
	
	МассивТипов = Новый Массив;
	МассивТипов.Добавить(ТипЗначенияОбъектаИБ);
	ОписаниеТипов = Новый ОписаниеТипов(МассивТипов);
	ПустаяСсылка = ОписаниеТипов.ПривестиЗначение();

	МенеджерОбъектаМетаданных = ОбщегоНазначения.МенеджерОбъектаПоСсылке(ПустаяСсылка);
	
	НайденнаяСсылка = МенеджерОбъектаМетаданных.ПолучитьСсылку(Новый УникальныйИдентификатор(УИДОбъектаXDTO));
	Если Не ЗначениеЗаполнено(УзелОбмена)
		Или НайденнаяСсылка.Пустая()
		Или Не ОбщегоНазначения.СсылкаСуществует(НайденнаяСсылка) Тогда
		Возврат НайденнаяСсылка;
	КонецЕсли;
	СтруктураЗаписи = Новый Структура;
	СтруктураЗаписи.Вставить("Ссылка", НайденнаяСсылка);
	СтруктураЗаписи.Вставить("УзелИнформационнойБазы", УзелОбмена);
	
	ИспользоватьКешПубличныхИдентификаторов = КомпонентыОбмена.ИспользоватьКешПубличныхИдентификаторов;
	
	Если НЕ ИспользоватьКешПубличныхИдентификаторов 
		И НЕ РегистрыСведений.ПубличныеИдентификаторыСинхронизируемыхОбъектов.ЗаписьЕстьВРегистре(СтруктураЗаписи) Тогда
		
		Возврат НайденнаяСсылка;
		
	ИначеЕсли ИспользоватьКешПубличныхИдентификаторов 
		И Не ЗаписьЕстьВКешеПубличныхИдентификаторов(СтруктураЗаписи, КомпонентыОбмена) Тогда
		
		Возврат НайденнаяСсылка;
		
	КонецЕсли;
	
	// Данному УИД уже сопоставлен другой объект. Нужно создавать ссылку с другим УИДом.
	НоваяСсылка = МенеджерОбъектаМетаданных.ПолучитьСсылку();
	
	Возврат НоваяСсылка;
	
КонецФункции

Функция НайтиСсылкуПоПубличномуИдентификатору(УИДОбъектаXDTO, КомпонентыОбмена, ТипЗначенияОбъектаИБ)
		
	УзелКорреспондента = КомпонентыОбмена.УзелКорреспондента;
	
	Если Не ЗначениеЗаполнено(УзелКорреспондента) Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
	
	Если Не КомпонентыОбмена.ИспользоватьКешПубличныхИдентификаторов Тогда
	
		Запрос = Новый Запрос(
			"ВЫБРАТЬ
			|	РПИ.Ссылка КАК Ссылка
			|ИЗ
			|	РегистрСведений.ПубличныеИдентификаторыСинхронизируемыхОбъектов КАК РПИ
			|ГДЕ
			|	РПИ.УзелИнформационнойБазы = &УзелИнформационнойБазы
			|	И РПИ.Идентификатор = &Идентификатор");
		
		Запрос.УстановитьПараметр("УзелИнформационнойБазы", УзелКорреспондента);
		Запрос.УстановитьПараметр("Идентификатор",          УИДОбъектаXDTO);
				
		Результат = Запрос.Выполнить().Выгрузить();
			
	Иначе
	
		КешПубличныхИдентификаторов = КомпонентыОбмена.КешПубличныхИдентификаторов;
		
		Отбор = Новый Структура("Идентификатор", УИДОбъектаXDTO);
		Результат = КешПубличныхИдентификаторов.НайтиСтроки(Отбор);
		
	КонецЕсли;
	
	НайденнаяСсылка    = Неопределено;
	НекорректныеСсылки = Новый Массив;
	УдалитьВсеЗаписи   = Ложь;
	
	Для Каждого Строка Из Результат Цикл
			
		Если ТипЗнч(Строка.Ссылка) <> ТипЗначенияОбъектаИБ Тогда
			Продолжить;
		КонецЕсли;
		
		Если НайденнаяСсылка = Неопределено Тогда
			НайденнаяСсылка = Строка.Ссылка;
		ИначеЕсли ОбщегоНазначения.СсылкаСуществует(Строка.Ссылка) Тогда
			Если ОбщегоНазначения.СсылкаСуществует(НайденнаяСсылка) Тогда
				УдалитьВсеЗаписи = Истина;
				НайденнаяСсылка  = Неопределено;
				Прервать;
			Иначе
				// Удаление битой ссылки.
				НекорректныеСсылки.Добавить(НайденнаяСсылка);
				
				НайденнаяСсылка = Строка.Ссылка;
			КонецЕсли;
		Иначе
			// Удаление битой ссылки.
			НекорректныеСсылки.Добавить(Строка.Ссылка);
		КонецЕсли;
		
	КонецЦикла;
	
	ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
		ВремяНачала, "ПоискСсылок", "", КомпонентыОбмена,
		ОбменДаннымиОценкаПроизводительности.ТипСобытияБиблиотека());
		
	Если НайденнаяСсылка <> Неопределено
		И НекорректныеСсылки.Количество() > 0
		И Не ОбщегоНазначения.СсылкаСуществует(НайденнаяСсылка) Тогда
		УдалитьВсеЗаписи = Истина;
		НайденнаяСсылка  = Неопределено;
	КонецЕсли;
	
	Если УдалитьВсеЗаписи Тогда
		
		СтруктураЗаписи = Новый Структура;
		СтруктураЗаписи.Вставить("Идентификатор",          УИДОбъектаXDTO);
		СтруктураЗаписи.Вставить("УзелИнформационнойБазы", УзелКорреспондента);
		
		РегистрыСведений.ПубличныеИдентификаторыСинхронизируемыхОбъектов.УдалитьЗапись(СтруктураЗаписи, Истина);
		
		УдалитьЗаписьИзКешаПубличныхИдентификаторов(СтруктураЗаписи, КомпонентыОбмена);
		
	ИначеЕсли НекорректныеСсылки.Количество() > 0 Тогда
		
		СтруктураЗаписи = Новый Структура;
		СтруктураЗаписи.Вставить("Идентификатор",          УИДОбъектаXDTO);
		СтруктураЗаписи.Вставить("УзелИнформационнойБазы", УзелКорреспондента);
		
		Для Каждого Ссылка Из НекорректныеСсылки Цикл
			СтруктураЗаписи.Вставить("Ссылка", Ссылка);
			РегистрыСведений.ПубличныеИдентификаторыСинхронизируемыхОбъектов.УдалитьЗапись(СтруктураЗаписи, Истина);
			
			УдалитьЗаписьИзКешаПубличныхИдентификаторов(СтруктураЗаписи, КомпонентыОбмена);
		КонецЦикла;
		
	КонецЕсли;
	
	Возврат НайденнаяСсылка;
	
КонецФункции

// Чтение и обработка данных об удалении объекта.
//
// Параметры:
//  КомпонентыОбмена        - Структура - содержит все правила и параметры обмена.
//  ОбъектXDTO              - ОбъектXDTO - объект пакета XDTO "УдалениеОбъекта", который содержит информацию об
//                            удаленном объекте информационной базы.
//  МассивОбъектовКУдалению - Массив из ЛюбаяСсылка - массив в который будет помещена ссылка на объект, подлежащий удалению.
//                            Собственно удаление объектов происходит после загрузки всех данных, при этом учитывается
//                            какие объекты были загружены (не удаляются ссылки, которые были загружены как другие
//                            ОбъектыXDTO).
//  ТаблицыДляЗагрузки      - ТаблицаЗначений - коллекция загружаемых таблиц данных.
//
Процедура ПрочитатьУдаление(КомпонентыОбмена, ОбъектXDTO, МассивОбъектовКУдалению, ТаблицыДляЗагрузки = Неопределено)
	
	ТипСсылкиXDTO = Неопределено;
	
	Если Не ОбъектXDTO.Установлено("СсылкаНаОбъект") Тогда
		Возврат;
	КонецЕсли;
	
	Для Каждого СвойствоXDTO Из ОбъектXDTO.СсылкаНаОбъект.СсылкаНаОбъект.Свойства() Цикл
		
		Если Не ОбъектXDTO.СсылкаНаОбъект.СсылкаНаОбъект.Установлено(СвойствоXDTO) Тогда
			Продолжить;
		КонецЕсли;
		
		ЗначениеСвойстваXDTO = ОбъектXDTO.СсылкаНаОбъект.СсылкаНаОбъект.ПолучитьXDTO(СвойствоXDTO);
		ЗначениеСсылкиXDTO   = ПрочитатьЗначениеXDTOСложногоТипа(ЗначениеСвойстваXDTO, "Ссылка", ЗначениеСвойстваXDTO.Тип());
		
		// Определим тип ссылки
		ТипСсылкиXDTO = ЗначениеСсылкиXDTO.ТипЗначенияXDTO;
		УникальныйИдентификаторСтрокой = ЗначениеСсылкиXDTO.Значение;
		Прервать;
		
	КонецЦикла;
	
	Если ТипСсылкиXDTO = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	// Поиск ПОД
	ПОД = ПОДПоТипуСсылкиXDTO(КомпонентыОбмена, ТипСсылкиXDTO, Истина);
	
	Если Не ЗначениеЗаполнено(ПОД) Тогда
		Возврат;
	КонецЕсли;
		
	МассивИменПКО = ПОД.ИспользуемыеПКО;
	
	Для Каждого ПравилоКонвертацииИмя Из МассивИменПКО Цикл
		
		ПравилоКонвертации = КомпонентыОбмена.ПравилаКонвертацииОбъектов.Найти(ПравилоКонвертацииИмя, "ИмяПКО");
		Если ПравилоКонвертации = Неопределено Тогда
			
			Продолжить;
			
		КонецЕсли;
		
		Если Не ОбъектФорматаПроходитПоФильтруXDTO(КомпонентыОбмена, ПравилоКонвертации.ОбъектФормата) Тогда
			Продолжить;
		КонецЕсли;
		
		Если ПравилоКонвертации.ВариантИдентификации = "СначалаПоУникальномуИдентификаторуПотомПоПолямПоиска"
			Или ПравилоКонвертации.ВариантИдентификации = "ПоУникальномуИдентификатору" Тогда
			
			Если Не ОбъектПроходитПоФильтруТаблицДляЗагрузки(
					ТаблицыДляЗагрузки, ОбъектXDTO.Тип().Имя, ПравилоКонвертации.ТипПолученныхДанныхСтрокой) Тогда
				Продолжить;
			КонецЕсли;
			
			ДополнитьСписокОбъектовКУдалению(КомпонентыОбмена,
				ПравилоКонвертации.ТипДанных, УникальныйИдентификаторСтрокой, МассивОбъектовКУдалению);
			
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

Процедура ПрименитьУдалениеОбъектов(КомпонентыОбмена, МассивОбъектовКУдалению, МассивЗагруженныхОбъектов)
	
	Для Каждого ЗагруженныйОбъект Из МассивЗагруженныхОбъектов Цикл
		Пока МассивОбъектовКУдалению.Найти(ЗагруженныйОбъект) <> Неопределено Цикл
			МассивОбъектовКУдалению.Удалить(МассивОбъектовКУдалению.Найти(ЗагруженныйОбъект));
		КонецЦикла;
	КонецЦикла;
	
	ЗапретитьПроведениеДокумента = Метаданные.СвойстваОбъектов.Проведение.Запретить;
	
	Для Каждого ЭлементКУдалению Из МассивОбъектовКУдалению Цикл
		
		// Собственно удаление ссылки.
		Объект = ЭлементКУдалению.ПолучитьОбъект();
		Если Объект = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		Если КомпонентыОбмена.РежимЗагрузкиДанныхВИнформационнуюБазу Тогда
			
			Если КомпонентыОбмена.ЭтоОбменЧерезПланОбмена
				И ОбменДаннымиСобытия.ЗагрузкаЗапрещена(Объект, КомпонентыОбмена.УзелКорреспондентаОбъект) Тогда
				
				Продолжить; // Если изменение объекта ограничено датой запрета, то продолжим цикл
				
			КонецЕсли;
			
			МетаданныеОбъекта = Объект.Метаданные();
			Если Метаданные.Документы.Содержит(МетаданныеОбъекта) Тогда
				Если Объект.Проведен Тогда
					
					ЕстьРезультат = ОтменитьПроведениеОбъектаВИБ(Объект, 
						КомпонентыОбмена.УзелКорреспондента, КомпонентыОбмена);
					
					Если Не ЕстьРезультат Тогда
						Продолжить;
					КонецЕсли;
				ИначеЕсли МетаданныеОбъекта.Проведение = ЗапретитьПроведениеДокумента Тогда
					СделатьНеактивнымиДвиженияДокумента(Объект, КомпонентыОбмена);
				КонецЕсли;
			КонецЕсли;
			ОбменДаннымиСервер.УстановитьОбменДаннымиЗагрузка(Объект, Истина, Ложь, КомпонентыОбмена.УзелКорреспондента);
			УдалитьОбъект(Объект, Ложь, КомпонентыОбмена);
		Иначе
			
			ТипПолученныхДанныхСтрокой = ИмяТипаДанныхПоОбъектуМетаданных(Объект.Метаданные());
			
			СтрокаТаблицы = КомпонентыОбмена.ТаблицаДанныхЗаголовкаПакета.Добавить();
			
			СтрокаТаблицы.ТипОбъектаСтрокой = ТипПолученныхДанныхСтрокой;
			СтрокаТаблицы.КоличествоОбъектовВИсточнике = 1;
			СтрокаТаблицы.ТипПриемникаСтрокой = ТипПолученныхДанныхСтрокой;
			СтрокаТаблицы.ЭтоУдалениеОбъекта = Истина;
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

Процедура УдалитьОбъект(Объект, УдалитьНепосредственно, КомпонентыОбмена)
	
	Если Не РазрешенаЗаписьОбъекта(Объект, КомпонентыОбмена) Тогда
		СтрокаСообщенияОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			?(УдалитьНепосредственно,
				НСтр("ru = 'Попытка удаления неразделенных данных (%1: %2) в разделенном режиме.'"),
				НСтр("ru = 'Попытка пометки на удаление неразделенных данных (%1: %2) в разделенном режиме.'")),
			Объект.Метаданные().ПолноеИмя(),
			Строка(Объект));

		Если КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена = Неопределено
			Или КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Выполнено Тогда
			КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.ВыполненоСПредупреждениями;
		КонецЕсли;
		
		КодОшибки = Новый Структура;
		КодОшибки.Вставить("КраткоеПредставлениеОшибки",   СтрокаСообщенияОбОшибке);
		КодОшибки.Вставить("ПодробноеПредставлениеОшибки", СтрокаСообщенияОбОшибке);
		КодОшибки.Вставить("Уровень",                      УровеньЖурналаРегистрации.Предупреждение);
		
		ЗаписатьВПротоколВыполнения(КомпонентыОбмена, КодОшибки, , Ложь);
		
		Возврат;
	КонецЕсли;
	
	Предопределенный = Ложь;
	Если ОбщегоНазначенияКлиентСервер.ЕстьРеквизитИлиСвойствоОбъекта(Объект, "Предопределенный") Тогда
		Предопределенный = Объект.Предопределенный;
	КонецЕсли;
	
	Если Предопределенный Тогда
		Возврат;
	КонецЕсли;
	
	Если УдалитьНепосредственно Тогда
		Объект.Удалить();
	Иначе
		УстановитьПометкуУдаленияУОбъекта(Объект);
	КонецЕсли;
	
КонецПроцедуры

// Устанавливает пометку удаления.
//
// Параметры:
//  Объект          - объект для установки пометки.
//  ПометкаУдаления - Булево - флаг пометки удаления.
//  ИмяТипаОбъекта  - Строка - тип объекта строкой.
//
Процедура УстановитьПометкуУдаленияУОбъекта(Объект)
	
	Если Объект.ДополнительныеСвойства.Свойство("НайденЗапретЗагрузкиДанных") Тогда
		Возврат;
	КонецЕсли;
	МетаданныеОбъекта = Объект.Метаданные();
	Если ОбщегоНазначения.ЭтоДокумент(МетаданныеОбъекта) Тогда
		ОбменДаннымиСервер.УстановитьОбменДаннымиЗагрузка(Объект, Ложь);
		РегистрыСведений.РезультатыОбменаДанными.ЗарегистрироватьУстранениеПроблемы(Объект,
			Перечисления.ТипыПроблемОбменаДанными.НепроведенныйДокумент);
	КонецЕсли;
	
	ОбменДаннымиСервер.УстановитьОбменДаннымиЗагрузка(Объект);
	
	// Для иерархических объектов пометку удаления ставим только у конкретного объекта.
	Если ОбщегоНазначения.ЭтоСправочник(МетаданныеОбъекта)
		Или ОбщегоНазначения.ЭтоПланВидовХарактеристик(МетаданныеОбъекта)
		Или ОбщегоНазначения.ЭтоПланСчетов(МетаданныеОбъекта) Тогда
		Объект.УстановитьПометкуУдаления(Истина, Ложь);
	Иначе
		Объект.УстановитьПометкуУдаления(Истина);
	КонецЕсли;
	
КонецПроцедуры

Функция СообщениеОтНеобновленнойНастройки(ЧтениеXML)
	Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента
		И ЧтениеXML.ЛокальноеИмя = "ФайлОбмена" Тогда
		Пока ЧтениеXML.ПрочитатьАтрибут() Цикл
			Если ЧтениеXML.ЛокальноеИмя = "ВерсияФормата" 
				ИЛИ ЧтениеXML.ЛокальноеИмя = "ВерсияКонфигурацииИсточника" Тогда
				Возврат Истина;
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	Возврат Ложь;
КонецФункции

// Снимает признак активности движений документа.
//
// Параметры:
//  Объект      - ДокументОбъект - документ, движения которого необходимо обработать.
//  Отправитель - ПланОбменаСсылка - ссылка на узел плана обмена, который является отправителем данных.
//
// Возвращаемое значение:
//   Булево - признак успешного снятия активности с движений.
//
Функция СделатьНеактивнымиДвиженияДокумента(Объект, КомпонентыОбмена)
	
	Попытка
		
		ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
		
		Для Каждого Движение Из Объект.Движения Цикл
			
			Движение.Прочитать();
			ЕстьИзменения = Ложь;
			Для Каждого Строка Из Движение Цикл
				
				Если Строка.Активность = Ложь Тогда
					Продолжить;
				КонецЕсли;
				
				Строка.Активность   = Ложь;
				ЕстьИзменения = Истина;
				
			КонецЦикла;
			
			Если ЕстьИзменения Тогда
				Движение.Записывать = Истина;
				ОбменДаннымиСервер.УстановитьОбменДаннымиЗагрузка(Движение, Истина, Ложь, КомпонентыОбмена.УзелКорреспондента);
				Движение.Записать();
			КонецЕсли;
			
		КонецЦикла;
		
		Событие = "ОчисткаДвиженийДокумента." + Объект.Метаданные().ПолноеИмя();
		ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
			ВремяНачала, Событие, Объект, КомпонентыОбмена,
			ОбменДаннымиОценкаПроизводительности.ТипСобытияПравило());
		
	Исключение
		Возврат Ложь;
	КонецПопытки;
	
	Возврат Истина;
	
КонецФункции

Процедура ОбновитьПрефиксКорреспондента(КомпонентыОбмена)
	
	Если ЗначениеЗаполнено(КомпонентыОбмена.ПрефиксКорреспондента) Тогда
		Префиксы = РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.ПрефиксыУзла(КомпонентыОбмена.УзелКорреспондента);
		Если Не ЗначениеЗаполнено(Префиксы.ПрефиксКорреспондента) Тогда
			РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.ОбновитьПрефиксы(
				КомпонентыОбмена.УзелКорреспондента, , КомпонентыОбмена.ПрефиксКорреспондента);
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Параметры:
//   КомпонентыОбмена - см. ОбменДаннымиXDTOСервер.ИнициализироватьКомпонентыОбмена
//
Процедура ОбновитьНастройкиXDTOКорреспондента(КомпонентыОбмена)
	
	// Проверяем возможность увеличения версии в корреспонденте.
	НомерВерсииКорреспондента  = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(КомпонентыОбмена.УзелКорреспондента, "ВерсияФорматаОбмена");
	МаксимальнаяОбщаяВерсия    = МаксимальнаяОбщаяВерсияФормата(
		ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(КомпонентыОбмена.УзелКорреспондента),
		КомпонентыОбмена.НастройкиXDTOКорреспондента.ПоддерживаемыеВерсии);
		
	Если МаксимальнаяОбщаяВерсия <> НомерВерсииКорреспондента Тогда
		НачатьТранзакцию();
		Попытка
		    Блокировка = Новый БлокировкаДанных;
		    ЭлементБлокировки = Блокировка.Добавить(ОбщегоНазначения.ИмяТаблицыПоСсылке(КомпонентыОбмена.УзелКорреспондента));
		    ЭлементБлокировки.УстановитьЗначение("Ссылка", КомпонентыОбмена.УзелКорреспондента);
		    Блокировка.Заблокировать();
		    
			ЗаблокироватьДанныеДляРедактирования(КомпонентыОбмена.УзелКорреспондента);
			УзелКорреспондентаОбъект = КомпонентыОбмена.УзелКорреспондента.ПолучитьОбъект();
			
			УзелКорреспондентаОбъект.ВерсияФорматаОбмена = МаксимальнаяОбщаяВерсия;

			УзелКорреспондентаОбъект.Записать();
			
			ЗафиксироватьТранзакцию();
		Исключение
		    ОтменитьТранзакцию();
		    ВызватьИсключение;
		КонецПопытки;
		
		ЗаписатьВПротоколВыполнения(КомпонентыОбмена, 
			НСтр("ru = 'Изменен номер версии формата обмена.'"), , Ложь, , , Истина);
	КонецЕсли;
	
	РегистрыСведений.НастройкиОбменаДаннымиXDTO.ОбновитьНастройкиКорреспондента(КомпонентыОбмена.УзелКорреспондента,
		"ПоддерживаемыеОбъекты",
		КомпонентыОбмена.НастройкиXDTOКорреспондента.ПоддерживаемыеОбъекты);
	РегистрыСведений.НастройкиОбменаДаннымиXDTO.ОбновитьНастройкиКорреспондента(КомпонентыОбмена.УзелКорреспондента,
		"ПоддерживаемыеРасширения",
		КомпонентыОбмена.НастройкиXDTOКорреспондента.ПоддерживаемыеРасширения);
	
КонецПроцедуры

Процедура ЗаполнитьСтруктуруНастроекXDTO(КомпонентыОбмена) Экспорт
	
	Если Не КомпонентыОбмена.ЭтоОбменЧерезПланОбмена
		Или Не ЗначениеЗаполнено(КомпонентыОбмена.УзелКорреспондента) Тогда
		Возврат;
	КонецЕсли;
	
	ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(КомпонентыОбмена.УзелКорреспондента);
	
	КомпонентыОбмена.НастройкиXDTO.Формат = ФорматОбмена(ИмяПланаОбмена, "");
	РасширенияФорматаВКомпонентыОбмена(КомпонентыОбмена);
	
	Если КомпонентыОбмена.НаправлениеОбмена = "Отправка" Тогда
		
		КомпонентыОбмена.НастройкиXDTO.ПоддерживаемыеОбъекты = 
			ПоддерживаемыеОбъектыФормата(ИмяПланаОбмена, "ОтправкаПолучение", КомпонентыОбмена.УзелКорреспондента);
		
	Иначе
		
		ТаблицаОбъекты = Новый ТаблицаЗначений;
		ИнициализироватьТаблицуПоддерживаемыхОбъектовФормата(ТаблицаОбъекты, КомпонентыОбмена.НаправлениеОбмена);
		
		ЗаполнитьПоддерживаемыеОбъектыФорматаПоКомпонентамОбмена(ТаблицаОбъекты, КомпонентыОбмена);
		
		ИмяАлгоритма = "ПриОпределенииПоддерживаемыхОбъектовФормата";
		ЕстьАлгоритм = ОбменДаннымиСервер.ЕстьАлгоритмМенеджераПланаОбмена(ИмяАлгоритма, ИмяПланаОбмена);
		Если ЕстьАлгоритм Тогда
			ПланыОбмена[ИмяПланаОбмена].ПриОпределенииПоддерживаемыхОбъектовФормата(
				ТаблицаОбъекты, КомпонентыОбмена.НаправлениеОбмена, КомпонентыОбмена.УзелКорреспондента);
		КонецЕсли;
		
		КомпонентыОбмена.НастройкиXDTO.ПоддерживаемыеОбъекты = ТаблицаОбъекты;
		
	КонецЕсли;
	
	КомпонентыОбмена.НастройкиXDTO.ПоддерживаемыеВерсии = ВерсииФорматаОбменаМассив(КомпонентыОбмена.УзелКорреспондента);
	
КонецПроцедуры

// Параметры:
//   СтруктураНастроек - Структура:
//     * Формат - Строка - имя формата обмена.
//     * ПоддерживаемыеВерсии - Массив из Строка - коллекция поддерживаемых версий формата.
//     * ПоддерживаемыеОбъекты - см. ПоддерживаемыеОбъектыФормата
//   Header - ОбъектXDTO - заголовок сообщения обмена.
//   ФорматСодержитВерсию - Булево - Истина, если строка формата содержит номер версии.
//   УзелОбмена - ПланОбменаСсылка
//              - Неопределено - узел плана обмена.
//
Процедура ЗаполнитьСтруктуруНастроекXDTOКорреспондента(СтруктураНастроек,
		Header, ФорматСодержитВерсию = Истина, УзелОбмена = Неопределено) Экспорт
	
	Если ФорматСодержитВерсию Тогда
		ФорматОбмена = РазложитьФорматОбмена(Header.Format);
		СтруктураНастроек.Формат = ФорматОбмена.БазовыйФормат;
	Иначе
		СтруктураНастроек.Формат = Header.Format;
	КонецЕсли;
	
	Для Каждого AvailableVersion Из Header.AvailableVersion Цикл
		СтруктураНастроек.ПоддерживаемыеВерсии.Добавить(AvailableVersion);
	КонецЦикла;
	
	Если Не Header.Установлено("AvailableObjectTypes")
		И Не УзелОбмена = Неопределено
		И ФорматСодержитВерсию Тогда
		// Обратная совместимость с 2.x.
		// Поскольку от корреспондента нет и не может быть получено информации о поддержке объектов,
		// принимаем, что он умеет отправлять все объекты, которые эта база может получать,
		// и может получать все объекты, которые эта база может отправлять.
		// В качестве версии формата принимается максимальная общая версия.
		
		ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелОбмена);
		
		ТаблицаОбъектыБазы = ПоддерживаемыеОбъектыФормата(ИмяПланаОбмена,
			"ОтправкаПолучение", ?(УзелОбмена.Пустая(), Неопределено, УзелОбмена));
		
		Для Каждого Версия Из СтруктураНастроек.ПоддерживаемыеВерсии Цикл
			ОтборПоВерсии = Новый Структура("Версия", Версия);
			
			СтрокиОбъектыБазы = ТаблицаОбъектыБазы.НайтиСтроки(ОтборПоВерсии);
			Для Каждого СтрокаОбъектыБазы Из СтрокиОбъектыБазы Цикл
				
				СтрокаОбъектыКорреспондента = СтруктураНастроек.ПоддерживаемыеОбъекты.Добавить();
				ЗаполнитьЗначенияСвойств(СтрокаОбъектыКорреспондента, СтрокаОбъектыБазы, "Версия, Объект");
				СтрокаОбъектыКорреспондента.Отправка = СтрокаОбъектыБазы.Получение;
				СтрокаОбъектыКорреспондента.Получение = СтрокаОбъектыБазы.Отправка;
				
			КонецЦикла;
		КонецЦикла;
		
		Возврат;
	КонецЕсли;
	
	Если Header.AvailableObjectTypes <> Неопределено Тогда
		
		Для Каждого ObjectType Из Header.AvailableObjectTypes.ObjectType Цикл
		
			Отправка  = Новый Массив;
			Получение = Новый Массив;
			
			Если Не ПустаяСтрока(ObjectType.Sending) Тогда
				
				Если ObjectType.Sending = "*" Тогда
					Для Каждого Версия Из СтруктураНастроек.ПоддерживаемыеВерсии Цикл
						Отправка.Добавить(СокрЛП(Версия));
					КонецЦикла;
				Иначе
					Для Каждого Версия Из СтрРазделить(ObjectType.Sending, ",", Ложь) Цикл
						Отправка.Добавить(СокрЛП(Версия));
					КонецЦикла;
				КонецЕсли;
				
			КонецЕсли;
			
			Если Не ПустаяСтрока(ObjectType.Receiving) Тогда
				
				Если ObjectType.Receiving = "*" Тогда
					Для Каждого Версия Из СтруктураНастроек.ПоддерживаемыеВерсии Цикл
						Получение.Добавить(СокрЛП(Версия));
					КонецЦикла;
				Иначе
					Для Каждого Версия Из СтрРазделить(ObjectType.Receiving, ",", Ложь) Цикл
						Получение.Добавить(СокрЛП(Версия));
					КонецЦикла;
				КонецЕсли;
				
			КонецЕсли;
			
			Для Каждого Версия Из Отправка Цикл
				
				СтрокаОбъект = СтруктураНастроек.ПоддерживаемыеОбъекты.Добавить();
				СтрокаОбъект.Объект = ObjectType.Name;
				СтрокаОбъект.Версия = Версия;
				СтрокаОбъект.Отправка = Истина;
				
				Индекс = Получение.Найти(Версия);
				Если Не Индекс = Неопределено Тогда
					СтрокаОбъект.Получение = Истина;
					Получение.Удалить(Индекс);
				КонецЕсли;
				
			КонецЦикла;
			
			Для Каждого Версия Из Получение Цикл
				
				СтрокаОбъект = СтруктураНастроек.ПоддерживаемыеОбъекты.Добавить();
				СтрокаОбъект.Объект = ObjectType.Name;
				СтрокаОбъект.Версия = Версия;
				СтрокаОбъект.Получение = Истина;
				
			КонецЦикла;
			
		КонецЦикла;
		
	КонецЕсли;
	
	Если ТипЗнч(Header) = Тип("ОбъектXDTO")
		И Header.Свойства().Получить("AvailableExtensions") <> Неопределено // Свойство должно быть
		И Header.AvailableExtensions <> Неопределено						// и свойство должно быть заполненным (содержать данные)
		Тогда
		
		Для Каждого Extension Из Header.AvailableExtensions.Extension Цикл
			
			СтруктураНастроек.ПоддерживаемыеРасширения.Вставить(Extension.Namespace, Extension.BaseVersion);
			
		КонецЦикла;
		
	КонецЕсли;
	
КонецПроцедуры

Функция РазрешенаЗаписьОбъекта(Объект, КомпонентыОбмена)
	
	Если ОбщегоНазначения.РазделениеВключено()
		И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса") Тогда
			МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
			ЭтоРазделенныйОбъектМетаданных = МодульРаботаВМоделиСервиса.ЭтоРазделенныйОбъектМетаданных(Объект.Метаданные());
		Иначе
			ЭтоРазделенныйОбъектМетаданных = Ложь;
		КонецЕсли;
		
		Если Не ЭтоРазделенныйОбъектМетаданных Тогда
		
			Возврат Ложь;
			
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат Истина;
	
КонецФункции

#КонецОбласти

#Область ПоискПравилОбмена

Функция ПОДПоТипуСсылкиXDTO(КомпонентыОбмена, ТипСсылкиXDTO, ВозвращатьПустоеЗначение = Ложь)
	
	ПравилоОбработки = КомпонентыОбмена.ПравилаОбработкиДанных.Найти(ТипСсылкиXDTO, "ТипСсылкиXDTO");
	Если ПравилоОбработки = Неопределено Тогда
		
		Если ВозвращатьПустоеЗначение Тогда
			Возврат ПравилоОбработки;
		Иначе
			
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не найдено ПОД для типа ссылки XDTO.
					|Тип ссылки XDTO: %1
					|Описание ошибки: %2'"),
				Строка(ТипСсылкиXDTO),
				ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
				
		КонецЕсли;
		
	Иначе
		Возврат ПравилоОбработки;
	КонецЕсли;
	
КонецФункции

Функция ПОДПоТипуОбъектаXDTO(КомпонентыОбмена, ТипОбъектаXDTO, ВозвращатьПустоеЗначение = Ложь)
	
	ПравилоОбработки = КомпонентыОбмена.ПравилаОбработкиДанных.Найти(ТипОбъектаXDTO, "ОбъектВыборкиФормат");
	Если ПравилоОбработки = Неопределено Тогда
		
		Если ВозвращатьПустоеЗначение Тогда
			Возврат ПравилоОбработки;
		Иначе
			
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не найдено ПОД для типа объекта XDTO.
					|Тип объекта XDTO: %1
					|Описание ошибки: %2'"),
				Строка(ТипОбъектаXDTO),
				ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
				
		КонецЕсли;
		
	Иначе
		Возврат ПравилоОбработки;
	КонецЕсли;
	
КонецФункции

Функция ПОДПоОбъектуМетаданных(КомпонентыОбмена, ОбъектМетаданных)
	
	ПравилоОбработки = КомпонентыОбмена.ПравилаОбработкиДанных.Найти(ОбъектМетаданных, "ОбъектВыборкиМетаданные");
	
	Если ПравилоОбработки = Неопределено Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не найдено ПОД для объекта метаданных.
			|Объект метаданных: %3.'"),
			Строка(ОбъектМетаданных));
	КонецЕсли;
	
	Возврат ПравилоОбработки;

КонецФункции

Функция ПОДПоИмени(КомпонентыОбмена, Имя)
	
	ПравилоОбработки = КомпонентыОбмена.ПравилаОбработкиДанных.Найти(Имя, "Имя");
	
	Если ПравилоОбработки = Неопределено Тогда
		
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Не найдено ПОД с именем %1'"), Имя);
			
	Иначе
		Возврат ПравилоОбработки;
	КонецЕсли;

КонецФункции

Процедура ПолучитьПравилоОбработкиДляОбъекта(КомпонентыОбмена, Объект, ПравилоОбработки)
	
	Попытка
		ПравилоОбработки = ПОДПоОбъектуМетаданных(КомпонентыОбмена, Объект.Метаданные());
	Исключение
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Событие: %1.
			|Объект: %2.
			|
			|%3.'"),
			КомпонентыОбмена.НаправлениеОбмена,
			ПредставлениеОбъектаДляПротокола(Объект),
			ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
	КонецПопытки;
	
КонецПроцедуры

#КонецОбласти

#Область ОбработчикиСобытийПравилОбработкиДанных
// Процедура - "обертка" вызова обработчика ПОД ПриОбработке.
//
// Параметры:
//  КомпонентыОбмена - Структура - содержит все правила и параметры обмена.
//  ПравилоОбработки - строка таблицы правил обработки данных, соответствующая обрабатываемому ПОД
//  ОбъектОбработки  - ссылка на объект, подлежащий обработке
//                     либо структура, соответствующая объекту XDTO (при загрузке), 
//                     либо ссылка на объект информационной базы (при выгрузке).
//  ИспользованиеПКО - Структура - определяющая по каким ПКО будет выгружен объект
//                     ключи соответствуют именам ПКО, 
//                     значения - признак использования ПКО для конкретного объекта обработки.
//
Процедура ПриОбработкеПОД(КомпонентыОбмена, ПравилоОбработки, Знач ОбъектОбработки, ИспользованиеПКО, Отказ = Ложь)
	
	Если Не ЗначениеЗаполнено(ПравилоОбработки.ПриОбработке) Тогда
		Возврат;
	КонецЕсли;
		
	МенеджерОбмена = КомпонентыОбмена.МенеджерОбмена;
	СтруктураПараметров = Новый Структура();
	СтруктураПараметров.Вставить("ОбъектОбработки",  ОбъектОбработки);
	СтруктураПараметров.Вставить("ИспользованиеПКО", ИспользованиеПКО);
	СтруктураПараметров.Вставить("КомпонентыОбмена", КомпонентыОбмена);

	Попытка
		
		ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
		
		МенеджерОбмена.ВыполнитьПроцедуруМодуляМенеджера(ПравилоОбработки.ПриОбработке, СтруктураПараметров);
		
		ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
			ВремяНачала, ПравилоОбработки.ПриОбработке, ОбъектОбработки, КомпонентыОбмена,
			ОбменДаннымиОценкаПроизводительности.ТипСобытияПравило());
	
	Исключение
		Отказ = Истина;
		
		ОписаниеОшибки = ОписаниеОшибкиПОД(
			КомпонентыОбмена.НаправлениеОбмена,
			ПравилоОбработки.Имя,
			ПредставлениеОбъектаДляПротокола(ОбъектОбработки, ПравилоОбработки.ОбъектВыборкиМетаданные),
			ИнформацияОбОшибке());
		
		ЗафиксироватьПроблемуПриОбработкеОбъекта(КомпонентыОбмена,
			ОбъектОбработки,
			?(КомпонентыОбмена.НаправлениеОбмена = "Отправка",
				Перечисления.ТипыПроблемОбменаДанными.ОшибкаВыполненияКодаОбработчиковПриОтправкеДанных,
				Перечисления.ТипыПроблемОбменаДанными.ОшибкаВыполненияКодаОбработчиковПриПолученииДанных),
			ОписаниеОшибки.ПодробноеПредставление,
			ОписаниеОшибки.КраткоеПредставление);
	КонецПопытки;
	
	ОбъектОбработки  = СтруктураПараметров.ОбъектОбработки;
	ИспользованиеПКО = СтруктураПараметров.ИспользованиеПКО;
	КомпонентыОбмена = СтруктураПараметров.КомпонентыОбмена;
	
КонецПроцедуры

// Функция - "обертка" вызова обработчика ПОД ВыборкаДанных.
//
// Параметры:
//  КомпонентыОбмена - Структура - содержит все правила и параметры обмена.
//  ПравилоОбработки - СтрокаТаблицыЗначений - строка правил обработки данных, соответствующая обрабатываемому ПОД.
//
// Возвращаемое значение:
//  Произвольный - то, что вернет обработчик ВыборкаДанных, например, выборка результата запроса.
//
Функция ВыборкаДанных(КомпонентыОбмена, ПравилоОбработки)
	
	АлгоритмВыборки = ПравилоОбработки.ВыборкаДанных;
	Если ЗначениеЗаполнено(АлгоритмВыборки) Тогда
		
		МенеджерОбмена = КомпонентыОбмена.МенеджерОбмена;
		СтруктураПараметров = Новый Структура();
		СтруктураПараметров.Вставить("КомпонентыОбмена", КомпонентыОбмена);
		
		Попытка
			ВыборкаДанных = МенеджерОбмена.ВыполнитьФункциюМодуляМенеджера(ПравилоОбработки.ВыборкаДанных, СтруктураПараметров);
		Исключение
			
			ШаблонОписанияОшибки = НСтр("ru = 'Событие: %1.
					|Обработчик: %2.
					|ПОД: %3.
					|
					|Ошибка выполнения обработчика.
					|%4.'");
			
			ТекстОшибки = Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,
				КомпонентыОбмена.НаправлениеОбмена,
				"ВыборкаДанных",
				ПравилоОбработки.Имя,
				ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
				
			ВызватьИсключение ТекстОшибки;
			
		КонецПопытки;
		
	Иначе
		
		ТекстЗапроса =
		"ВЫБРАТЬ
		|	ПсевдонимТаблицыМетаданных.Ссылка
		|ИЗ
		|	&ИмяТаблицыМетаданных КАК ПсевдонимТаблицыМетаданных";
		
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицыМетаданных", ПравилоОбработки.ИмяТаблицыДляВыборки);
		
		Запрос = Новый Запрос(ТекстЗапроса);
		ВыборкаДанных = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
		
	КонецЕсли;
	
	Возврат ВыборкаДанных;
	
КонецФункции

#КонецОбласти

#Область ОбработчикиСобытийПравилКонвертации
// Функция - "обертка" вызова обработчика ПКО ПриОтправкеДанных.
//
// Параметры:
//  ДанныеИБ         - ссылка на выгружаемый объект информационной базы.
//                     Может быть также структура ключевых свойств, если выгружается не объект, а ссылка.
//  ДанныеXDTO       - Структура - в которую выгружаются данные. По составу идентичная объекту XDTO.
//  ИмяОбработчика   - Строка - имя процедуры-обработчика в модуле менеджера.
//  КомпонентыОбмена - Структура - содержит все правила и параметры обмена.
//  СтекВыгрузки     - Массив - содержит ссылки на выгружаемые объекты с учетом вложенности.
//
Процедура ПриОтправкеДанных(ДанныеИБ, ДанныеXDTO, Знач ИмяОбработчика, КомпонентыОбмена, СтекВыгрузки)
		
	МенеджерОбмена = КомпонентыОбмена.МенеджерОбмена;
	СтруктураПараметров = Новый Структура();
	СтруктураПараметров.Вставить("ДанныеИБ", ДанныеИБ);
	СтруктураПараметров.Вставить("ДанныеXDTO", ДанныеXDTO);
	СтруктураПараметров.Вставить("КомпонентыОбмена", КомпонентыОбмена);
	СтруктураПараметров.Вставить("СтекВыгрузки", СтекВыгрузки);

	Попытка
		
		ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
		
		МенеджерОбмена.ВыполнитьПроцедуруМодуляМенеджера(ИмяОбработчика, СтруктураПараметров);
		
		ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер( 
			ВремяНачала, ИмяОбработчика, ДанныеИБ, КомпонентыОбмена,
			ОбменДаннымиОценкаПроизводительности.ТипСобытияПравило());
		
	Исключение
		
		ШаблонОписанияОшибки = НСтр("ru = 'Событие: %1.
				|Обработчик: %2.
				|Объект: %3.
				|
				|Ошибка выполнения обработчика.
				|%4.'");
		
		ТекстОшибки = Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,
			КомпонентыОбмена.НаправлениеОбмена,
			"ПриОтправкеДанных",
			ПредставлениеОбъектаДляПротокола(ДанныеИБ),
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			
		ВызватьИсключение ТекстОшибки;
		
	КонецПопытки;
	
	ДанныеXDTO       = СтруктураПараметров.ДанныеXDTO;
	КомпонентыОбмена = СтруктураПараметров.КомпонентыОбмена;
	СтекВыгрузки     = СтруктураПараметров.СтекВыгрузки;
	
КонецПроцедуры

// Функция - "обертка" вызова обработчика ПКО ПриКонвертацииДанныхXDTO.
//
// Параметры:
//  ПолученныеДанные - объект информационной базы, в который происходит загрузка данных.
//  ДанныеXDTO       - Структура - из которой загружаются данные. По составу идентичная загружаемому объекту XDTO.
//  КомпонентыОбмена - Структура - содержит все правила и параметры обмена.
//  ИмяОбработчика   - Строка - имя процедуры-обработчика в модуле менеджера.
//
Процедура ПриКонвертацииДанныхXDTO(ДанныеXDTO, ПолученныеДанные, КомпонентыОбмена, Знач ИмяОбработчика)
	
	МенеджерОбмена = КомпонентыОбмена.МенеджерОбмена;
	СтруктураПараметров = Новый Структура();
	СтруктураПараметров.Вставить("ДанныеXDTO", ДанныеXDTO);
	СтруктураПараметров.Вставить("ПолученныеДанные", ПолученныеДанные);
	СтруктураПараметров.Вставить("КомпонентыОбмена", КомпонентыОбмена);
	
	Попытка
		
		ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
		
		МенеджерОбмена.ВыполнитьПроцедуруМодуляМенеджера(ИмяОбработчика, СтруктураПараметров);
		
		ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер( 
			ВремяНачала, ИмяОбработчика, ПолученныеДанные, КомпонентыОбмена,
			ОбменДаннымиОценкаПроизводительности.ТипСобытияПравило());
		
	Исключение
		
		ШаблонОписанияОшибки = НСтр("ru = 'Событие: %1.
				|Обработчик: %2.
				|Объект: %3.
				|
				|Ошибка выполнения обработчика.
				|%4.'");
		
		ТекстОшибки = Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,
			КомпонентыОбмена.НаправлениеОбмена,
			"ПриКонвертацииДанныхXDTO",
			ПредставлениеОбъектаДляПротокола(ПолученныеДанные),
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			
		ВызватьИсключение ТекстОшибки;
		
	КонецПопытки;
	
	ДанныеXDTO               = СтруктураПараметров.ДанныеXDTO;
	ПолученныеДанные         = СтруктураПараметров.ПолученныеДанные;
	КомпонентыОбмена         = СтруктураПараметров.КомпонентыОбмена;
	
КонецПроцедуры

// Функция - "обертка" вызова обработчика ПКО ПередЗаписьюПолученныхДанных.
//
// Параметры:
//  ПолученныеДанные   - объект информационной базы, в который происходит загрузка данных.
//  ДанныеИБ           - объект информационной базы, который найден при идентификации загружаемых данных.
//                       Если объект соответствующий загружаемому не найден, ДанныеИБ = Неопределено.
//  КомпонентыОбмена   - Структура - содержит все правила и параметры обмена.
//  ИмяОбработчика     - Строка - имя процедуры-обработчика в модуле менеджера.
//  КонвертацияСвойств - ТаблицаЗначений - правила конвертации свойств объекта.
//                       Используется для определения состава свойств, подлежащих переносу из ПолученныеДанные в
//                       ДанныеИБ.
//
Процедура ПередЗаписьюПолученныхДанных(ПолученныеДанные, ДанныеИБ, КомпонентыОбмена, ИмяОбработчика, КонвертацияСвойств)

	МенеджерОбмена = КомпонентыОбмена.МенеджерОбмена;
	СтруктураПараметров = Новый Структура();
	СтруктураПараметров.Вставить("ДанныеИБ", ДанныеИБ);
	СтруктураПараметров.Вставить("ПолученныеДанные", ПолученныеДанные);
	СтруктураПараметров.Вставить("КомпонентыОбмена", КомпонентыОбмена);
	СтруктураПараметров.Вставить("КонвертацияСвойств", КонвертацияСвойств);

	Попытка
		
		ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
		
		МенеджерОбмена.ВыполнитьПроцедуруМодуляМенеджера(ИмяОбработчика, СтруктураПараметров);
		
		ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
			ВремяНачала, ИмяОбработчика, ДанныеИБ, КомпонентыОбмена,
			ОбменДаннымиОценкаПроизводительности.ТипСобытияПравило());
		
	Исключение
		
		ШаблонОписанияОшибки = НСтр("ru = 'Событие: %1.
				|Обработчик: %2.
				|Объект: %3.
				|
				|Ошибка выполнения обработчика.
				|%4.'");
		
		ТекстОшибки = Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,
			КомпонентыОбмена.НаправлениеОбмена,
			"ПередЗаписьюПолученныхДанных",
			ПредставлениеОбъектаДляПротокола(?(ДанныеИБ <> Неопределено, ДанныеИБ, ПолученныеДанные)),
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			
		ВызватьИсключение ТекстОшибки;
		
	КонецПопытки;
	
	ДанныеИБ                 = СтруктураПараметров.ДанныеИБ;
	ПолученныеДанные         = СтруктураПараметров.ПолученныеДанные;
	КомпонентыОбмена         = СтруктураПараметров.КомпонентыОбмена;
	КонвертацияСвойств       = СтруктураПараметров.КонвертацияСвойств;
	
КонецПроцедуры

Процедура АлгоритмПоиска(ДанныеИБ, Знач ПолученныеДанные, Знач КомпонентыОбмена, Знач ИмяОбработчика)
	
	МенеджерОбмена = КомпонентыОбмена.МенеджерОбмена;
	СтруктураПараметров = Новый Структура();
	СтруктураПараметров.Вставить("ДанныеИБ", ДанныеИБ);
	СтруктураПараметров.Вставить("ПолученныеДанные", ПолученныеДанные);
	СтруктураПараметров.Вставить("КомпонентыОбмена", КомпонентыОбмена);

	Попытка
		МенеджерОбмена.ВыполнитьПроцедуруМодуляМенеджера(ИмяОбработчика, СтруктураПараметров);
	Исключение
		
		ШаблонОписанияОшибки = НСтр("ru = 'Событие: %1.
				|Обработчик: %2.
				|Объект: %3.
				|
				|Ошибка выполнения обработчика.
				|%4.'");
		
		ТекстОшибки = Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,
			КомпонентыОбмена.НаправлениеОбмена,
			"АлгоритмПоиска",
			ПредставлениеОбъектаДляПротокола(?(ДанныеИБ <> Неопределено, ДанныеИБ, ПолученныеДанные)),
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			
		ВызватьИсключение ТекстОшибки;
		
	КонецПопытки;
	
	ДанныеИБ                 = СтруктураПараметров.ДанныеИБ;
	ПолученныеДанные         = СтруктураПараметров.ПолученныеДанные;
	КомпонентыОбмена         = СтруктураПараметров.КомпонентыОбмена;
	
КонецПроцедуры

#КонецОбласти

#КонецОбласти

#Область ВедениеПротокола

// Возвращает объект типа структура, содержащий все возможные поля
// записи протокола выполнения (сообщения об ошибках и т.п.).
//
// Параметры:
//  КСообщенияОбОшибках - Строка - содержит код ошибки.
//  СтрокаОшибки        - Строка - содержит строку модуля где возникла ошибка.
//
// Возвращаемое значение:
//  Структура - объект типа структура
//
Функция ЗаписьПротоколаОбмена(КСообщенияОбОшибках = "", Знач СтрокаОшибки = "")

	СтруктураОшибки = Новый Структура(
		"ТипОбъекта,
		|Объект,
		|ОписаниеОшибки,
		|ПозицияМодуля,
		|КСообщенияОбОшибках");
	
	СтрокаМодуля = ОтделитьРазделителем(СтрокаОшибки, "{");
	Если ПустаяСтрока(СтрокаОшибки) Тогда
		ОписаниеОшибки = СокрЛП(ОтделитьРазделителем(СтрокаМодуля, "}:"));
	Иначе
		ОписаниеОшибки = СтрокаОшибки;
		СтрокаМодуля   = "{" + СтрокаМодуля;
	КонецЕсли;
	
	Если ОписаниеОшибки <> "" Тогда
		СтруктураОшибки.ОписаниеОшибки = ОписаниеОшибки;
		СтруктураОшибки.ПозицияМодуля  = СтрокаМодуля;
	КонецЕсли;
	
	Если СтруктураОшибки.КСообщенияОбОшибках <> "" Тогда
		
		СтруктураОшибки.КСообщенияОбОшибках = КСообщенияОбОшибках;
		
	КонецЕсли;
	
	Возврат СтруктураОшибки;
	
КонецФункции

Функция РезультатВыполненияОбменаОшибка(РезультатВыполненияОбмена)
	
	Возврат РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка
		Или РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка_ТранспортСообщения;
	
КонецФункции

Функция РезультатВыполненияОбменаПредупреждение(РезультатВыполненияОбмена)
	
	Возврат РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.ВыполненоСПредупреждениями
		Или РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Предупреждение_СообщениеОбменаБылоРанееПринято;
	
КонецФункции

// Функция формирует представление объекта, для записи в протокол обмена.
//
// Параметры:
//   Объект - ЛюбаяСсылка - ссылка на любой ОМД;
//          - Объект - ОМД;
//          - ОбъектXDTO - объект XDTO;
//          - Структура.
//   МетаданныеДляПредставленияСтруктуры - ОбъектМетаданных - метаданные объекта, для которого формируется представление.
//
// Возвращаемое значение:
//   Строка - строковое представление объекта.
//
Функция ПредставлениеОбъектаДляПротокола(Объект, МетаданныеДляПредставленияСтруктуры = Неопределено)
	
	ТипОбъекта           = ТипЗнч(Объект);
	МетаданныеОбъекта    = Метаданные.НайтиПоТипу(ТипОбъекта);
	ПредставлениеОбъекта = Строка(Объект);
	НавигационнаяСсылка  = "";
	
	Если МетаданныеОбъекта <> Неопределено
		И ОбщегоНазначения.ЭтоОбъектСсылочногоТипа(МетаданныеОбъекта)
		И ЗначениеЗаполнено(Объект.Ссылка) Тогда
		НавигационнаяСсылка = ПолучитьНавигационнуюСсылку(Объект.Ссылка);
	Иначе
		
		Если ТипОбъекта = Тип("ОбъектXDTO") Тогда
			
			КоллекцияСвойств = Объект.Свойства();
			ПредставлениеОбъекта = "";
			ТипОбъекта = Объект.Тип().Имя;
			
			Если КоллекцияСвойств.Количество() > 0 И КоллекцияСвойств.Получить(КлассКлючевыеСвойства()) <> Неопределено Тогда
				КлючевыеСвойства = Объект.Получить(КлассКлючевыеСвойства());
				
				Реквизиты = Новый Структура("Наименование, Код, КодВПрограмме, Номер, Дата"); // @Non-NLS
				ЗаполнитьЗначенияСвойств(Реквизиты, КлючевыеСвойства);
				
				ПредставлениеОбъекта = ПредставлениеКоллекцииСвойствДляПротокола(Реквизиты);
			КонецЕсли;
			
		ИначеЕсли ТипОбъекта = Тип("Структура") Тогда
			
			СформироватьПредставлениеДляСтруктуры = Истина;
			Если Объект.Свойство("Ссылка")
				И ЗначениеЗаполнено(Объект.Ссылка) Тогда
				ТипОбъекта = ТипЗнч(Объект.Ссылка);
				Если ОбщегоНазначения.ЭтоСсылка(ТипОбъекта) Тогда
					ПредставлениеОбъекта = Строка(Объект.Ссылка);
					НавигационнаяСсылка  = ПолучитьНавигационнуюСсылку(Объект.Ссылка);
					
					СформироватьПредставлениеДляСтруктуры = Ложь;
				КонецЕсли;
			КонецЕсли;
			
			Если СформироватьПредставлениеДляСтруктуры Тогда
				ТипОбъекта = Строка(ТипЗнч(Объект));
				Если Не МетаданныеДляПредставленияСтруктуры = Неопределено Тогда
					ТипОбъекта = ТипОбъекта + "<" + МетаданныеДляПредставленияСтруктуры.Представление() + ">";
				КонецЕсли;
				
				ПредставлениеОбъекта = ПредставлениеКоллекцииСвойствДляПротокола(Объект);
			КонецЕсли;
			
		КонецЕсли;
	КонецЕсли;
	
	ПредставлениеОбъекта = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '%1, %2 (%3)'"),
		ТипОбъекта, ПредставлениеОбъекта, НавигационнаяСсылка);
	
	Возврат ПредставлениеОбъекта;
	
КонецФункции

Функция ПредставлениеКоллекцииСвойствДляПротокола(КоллекцияСвойств)
	
	Представление = Строка(КоллекцияСвойств);
	
	ЭлементыПредставления = Новый Массив;
				
	ЗначениеСвойства = Неопределено;
	
	Если КоллекцияСвойств.Свойство("Наименование", ЗначениеСвойства) // @Non-NLS
		И ЗначениеЗаполнено(ЗначениеСвойства) Тогда
		ЭлементыПредставления.Добавить(СокрЛП(ЗначениеСвойства));
	КонецЕсли;
	
	Если КоллекцияСвойств.Свойство("Код", ЗначениеСвойства) // @Non-NLS
		И ЗначениеЗаполнено(ЗначениеСвойства) Тогда
		ЭлементыПредставления.Добавить("(" + СокрЛП(ЗначениеСвойства) + ")");
	ИначеЕсли КоллекцияСвойств.Свойство("КодВПрограмме", ЗначениеСвойства) // @Non-NLS
		И ЗначениеЗаполнено(ЗначениеСвойства) Тогда
		ЭлементыПредставления.Добавить("(" + СокрЛП(ЗначениеСвойства) + ")");
	КонецЕсли;
	
	Если КоллекцияСвойств.Свойство("Номер", ЗначениеСвойства) // @Non-NLS
		И ЗначениеЗаполнено(ЗначениеСвойства) Тогда
		
		ЗначениеСвойстваДата = Неопределено;
		Если КоллекцияСвойств.Свойство("Дата", ЗначениеСвойстваДата) // @Non-NLS
			И ЗначениеЗаполнено(ЗначениеСвойстваДата) Тогда
			ЭлементыПредставления.Добавить(
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '№%1 от %2'"), ЗначениеСвойства, Формат(ЗначениеСвойстваДата, "ДЛФ=D")));
		Иначе
			ЭлементыПредставления.Добавить(
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '№%1'"), ЗначениеСвойства));
		КонецЕсли;
		
	ИначеЕсли КоллекцияСвойств.Свойство("Дата", ЗначениеСвойства) // @Non-NLS
		И ЗначениеЗаполнено(ЗначениеСвойства) Тогда
		
		ЭлементыПредставления.Добавить(
			СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'от %1'"), ЗначениеСвойства));
		
	КонецЕсли;
	
	Если ЭлементыПредставления.Количество() > 0 Тогда
		Представление = СтрСоединить(ЭлементыПредставления, " ");
	КонецЕсли;
	
	Возврат Представление;
	
КонецФункции

Функция ПредставлениеОбъектаXDTOДляПротокола(ТипОбъектаXDTO)
	
	Возврат ТипОбъектаXDTO.Имя;
	
КонецФункции

#КонецОбласти

#Область РезультатыОбменаДанными

Функция ОписаниеОшибкиПОД(НаправлениеОбмена, ИмяПОД, ПредставлениеОбъекта, Информация)
	
	Результат = Новый Структура("КраткоеПредставление, ПодробноеПредставление");
	
	ШаблонОписанияОшибки = НСтр("ru = 'Событие: %1.
		|Обработчик: %2.
		|ПОД: %3.
		|Объект: %4.
		|
		|Ошибка выполнения обработчика.
		|%5.'");
	
	Результат.КраткоеПредставление = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		ШаблонОписанияОшибки,
		НаправлениеОбмена,
		"ПриОбработкеПОД",
		ИмяПОД,
		ПредставлениеОбъекта,
		ОбработкаОшибок.КраткоеПредставлениеОшибки(Информация));
		
	Результат.ПодробноеПредставление = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		ШаблонОписанияОшибки,
		НаправлениеОбмена,
		"ПриОбработкеПОД",
		ИмяПОД,
		ПредставлениеОбъекта,
		ОбработкаОшибок.ПодробноеПредставлениеОшибки(Информация));
	
	Возврат Результат;
	
КонецФункции

Функция ОписаниеОшибкиПКО(НаправлениеОбмена, ИмяПОД, ИмяПКО, ПредставлениеОбъекта, Информация)
	
	Результат = Новый Структура("КраткоеПредставление, ПодробноеПредставление");
	
	ШаблонОписанияОшибки = НСтр("ru = 'Направление: %1.
		|ПОД: %2.
		|ПКО: %3.
		|Объект: %4.
		|
		|%5'");
	
	Результат.КраткоеПредставление = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		ШаблонОписанияОшибки,
		НаправлениеОбмена,
		ИмяПОД,
		ИмяПКО,
		ПредставлениеОбъекта,
		ОбработкаОшибок.КраткоеПредставлениеОшибки(Информация));
		
	Результат.ПодробноеПредставление = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		ШаблонОписанияОшибки,
		НаправлениеОбмена,
		ИмяПОД,
		ИмяПКО,
		ПредставлениеОбъекта,
		ОбработкаОшибок.ПодробноеПредставлениеОшибки(Информация));
		
	Возврат Результат;
	
КонецФункции

Процедура ЗафиксироватьПроблемуПриОбработкеОбъекта(КомпонентыОбмена,
		ОбъектОбработки, ТипПроблемы, ПодробноеПредставление, КраткоеПредставление = "")
	
	КодОшибки = Новый Структура("Уровень", УровеньОшибкиПоТипуПроблемы(КомпонентыОбмена, ТипПроблемы));
	КодОшибки.Вставить("ПодробноеПредставлениеОшибки", ПодробноеПредставление);
	КодОшибки.Вставить("КраткоеПредставлениеОшибки",
		?(ПустаяСтрока(КраткоеПредставление), ПодробноеПредставление, КраткоеПредставление));
	
	Если КомпонентыОбмена.ЭтоОбменЧерезПланОбмена Тогда
		Если КомпонентыОбмена.НаправлениеОбмена = "Отправка" Тогда
			ЗаписатьВПротоколВыполнения(КомпонентыОбмена, КодОшибки, , Не КомпонентыОбмена.ПропускатьОбъектыСОшибкамиПроверкиПоСхеме);
			ЗаписатьОшибкуОбработкиОбъектаПриОтправке(
				ОбъектОбработки,
				КомпонентыОбмена.УзелКорреспондента,
				КодОшибки.КраткоеПредставлениеОшибки,
				ТипПроблемы);
		Иначе
			ЗаписатьВПротоколВыполнения(КомпонентыОбмена, КодОшибки);
		КонецЕсли;
	Иначе
		ЗаписатьВПротоколВыполнения(КомпонентыОбмена, КодОшибки);
	КонецЕсли;
	
КонецПроцедуры

Процедура ЗаписатьОшибкуОбработкиОбъектаПриОтправке(ОбъектОбработки, УзелИнформационнойБазы, Причина, ТипПроблемы)
	
	Если ТипЗнч(ОбъектОбработки) = Тип("Структура") Тогда
		Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначения.ЭтоОбъектСсылочногоТипа(ОбъектОбработки.Метаданные()) Тогда
		РегистрыСведений.РезультатыОбменаДанными.ЗарегистрироватьОшибкуПроверкиОбъекта(
			ОбъектОбработки.Ссылка,
			УзелИнформационнойБазы,
			Причина,
			ТипПроблемы);
	Иначе
		РегистрыСведений.РезультатыОбменаДанными.ЗарегистрироватьОшибкуПроверкиОбъекта(
			ОбъектОбработки,
			УзелИнформационнойБазы,
			Причина,
			ТипПроблемы);
	КонецЕсли;

КонецПроцедуры

Функция УровеньОшибкиПоТипуПроблемы(КомпонентыОбмена, ТипПроблемы)
	
	Если ТипПроблемы = Перечисления.ТипыПроблемОбменаДанными.ОшибкаПроверкиСконвертированногоОбъекта Тогда
		Возврат ?(КомпонентыОбмена.ЭтоОбменЧерезПланОбмена
				И КомпонентыОбмена.ПропускатьОбъектыСОшибкамиПроверкиПоСхеме,
			УровеньЖурналаРегистрации.Предупреждение, УровеньЖурналаРегистрации.Ошибка);
	ИначеЕсли ТипПроблемы = Перечисления.ТипыПроблемОбменаДанными.АдминистративнаяОшибкаПриложения
		ИЛИ ТипПроблемы = Перечисления.ТипыПроблемОбменаДанными.ОшибкаВыполненияКодаОбработчиковПриОтправкеДанных
		ИЛИ ТипПроблемы = Перечисления.ТипыПроблемОбменаДанными.ОшибкаВыполненияКодаОбработчиковПриПолученииДанных Тогда
		Возврат УровеньЖурналаРегистрации.Ошибка;
	ИначеЕсли ТипПроблемы = Перечисления.ТипыПроблемОбменаДанными.НезаполненныеРеквизиты
		Или ТипПроблемы = Перечисления.ТипыПроблемОбменаДанными.НепроведенныйДокумент Тогда
		Возврат УровеньЖурналаРегистрации.Предупреждение;
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

#КонецОбласти

#Область ПроцедурыИФункцииВерсионированияФорматаОбмена

Функция ВерсииФорматаОбмена(Знач УзелИнформационнойБазы)
	
	ВерсииФорматаОбмена = Новый Соответствие;
	ИмяПланаОбмена = "";
	
	Если ЗначениеЗаполнено(УзелИнформационнойБазы) Тогда
		ИмяПланаОбмена = ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(УзелИнформационнойБазы);
		ВерсииФорматаОбмена = ОбменДаннымиСервер.ЗначениеНастройкиПланаОбмена(ИмяПланаОбмена, "ВерсииФорматаОбмена");
	Иначе
		ОбменДаннымиПереопределяемый.ПриПолученииДоступныхВерсийФормата(ВерсииФорматаОбмена);
	КонецЕсли;
	
	Если ВерсииФорматаОбмена.Количество() = 0 Тогда
		Если ЗначениеЗаполнено(УзелИнформационнойБазы) Тогда
			
			ШаблонОписанияОшибки = НСтр("ru = 'Не заданы версии формата обмена.
				|Имя плана обмена: %1
				|Процедура: %2'");
			
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,
				ИмяПланаОбмена,
				"ПолучитьВерсииФорматаОбмена(<ВерсииФорматаОбмена>)");
			
			ВызватьИсключение ТекстОшибки;
			
		Иначе
			
			ШаблонОписанияОшибки = НСтр("ru = 'Не заданы версии формата обмена.
				|Процедура: %1'");
			
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,
				"ОбменДаннымиПереопределяемый.ПриПолученииДоступныхВерсийФормата(<ВерсииФорматаОбмена>)");
			
			ВызватьИсключение ТекстОшибки;
			
		КонецЕсли;
	КонецЕсли;
	
	Результат = Новый Соответствие;
	
	Для Каждого Версия Из ВерсииФорматаОбмена Цикл
		
		Результат.Вставить(СокрЛП(Версия.Ключ), Версия.Значение);
		
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция СортироватьВерсииФормата(Знач ВерсииФормата)
	
	Результат = Новый ТаблицаЗначений;
	Результат.Колонки.Добавить("Версия");
	
	Для Каждого Версия Из ВерсииФормата Цикл
		
		Результат.Добавить().Версия = Версия.Ключ;
		
	КонецЦикла;
	
	Результат.Сортировать("Версия Убыв");
	
	Возврат Результат.ВыгрузитьКолонку("Версия");
КонецФункции

Процедура ПроверитьВерсию(Знач Версия)
	
	Версии = СтрРазделить(Версия, ".");
	
	Если Версии.Количество() = 0 Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Неканоническое представление версии формата обмена: <%1>.'"), Версия);
	КонецЕсли;
	
КонецПроцедуры

Функция МинимальнаяВерсияФорматаОбмена(Знач УзелИнформационнойБазы)
	
	Результат = Неопределено;
	
	ВерсииФормата = ВерсииФорматаОбмена(УзелИнформационнойБазы);
	
	Для Каждого ВерсияФормата Из ВерсииФормата Цикл
		
		Если Результат = Неопределено Тогда
			Результат = ВерсияФормата.Ключ;
			Продолжить;
		КонецЕсли;
		Если СравнитьВерсии(СокрЛП(Результат), СокрЛП(ВерсияФормата.Ключ)) > 0 Тогда
			Результат = ВерсияФормата.Ключ;
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

// Получает массив версий формата обмена, сортированные по убыванию.
// Параметры:
//  УзелИнформационнойБазы - ссылка на узел-корреспондент.
//
Функция ВерсииФорматаОбменаМассив(Знач УзелИнформационнойБазы) Экспорт
	
	Возврат СортироватьВерсииФормата(ВерсииФорматаОбмена(УзелИнформационнойБазы));
	
КонецФункции

// Сравнить две строки версий.
//
// Параметры:
//  СтрокаВерсии1  - Строка - номер версии в формате 0.0.0 либо 0.0.
//  СтрокаВерсии2  - Строка - второй сравниваемый номер версии.
//
// Возвращаемое значение:
//   Число   - больше 0, если СтрокаВерсии1 > СтрокаВерсии2; 0, если версии равны.
//             Меньше 0 если СтрокаВерсии1 < СтрокаВерсии2.
//
Функция СравнитьВерсии(Знач СтрокаВерсии1, Знач СтрокаВерсии2)
	
	Строка1 = ?(ПустаяСтрока(СтрокаВерсии1), "0.0", СтрокаВерсии1);
	Строка2 = ?(ПустаяСтрока(СтрокаВерсии2), "0.0", СтрокаВерсии2);
	Версия1 = СтрРазделить(Строка1, ".");
	
	ШаблонОписанияОшибки = НСтр("ru = 'Неправильный формат параметра %1: %2'");
	
	Если Версия1.Количество() < 2 ИЛИ Версия1.Количество() > 3 Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,"СтрокаВерсии1", СтрокаВерсии1);
	КонецЕсли;
	Версия2 = СтрРазделить(Строка2, ".");
	Если Версия2.Количество() < 2 ИЛИ Версия2.Количество() > 3 Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,"СтрокаВерсии2", СтрокаВерсии2);
	КонецЕсли;
	
	Результат = 0;
	Если СокрЛП(СтрокаВерсии1) = СокрЛП(СтрокаВерсии2) Тогда
		Возврат 0;
	КонецЕсли;
	
	// В последнем разряде может быть beta - это минимальная версия, не совместимая ни с какой другой.
	Если Версия1.Количество() = 3 И СокрЛП(Версия1[2]) = "beta" Тогда
		Возврат -1;
	ИначеЕсли Версия2.Количество() = 3 И СокрЛП(Версия2[2]) = "beta" Тогда
		Возврат 1;
	КонецЕсли;
	// Значимыми при сравнении являются первые 2 разряда (всегда число).
	Для Разряд = 0 По 1 Цикл
		Результат = Число(Версия1[Разряд]) - Число(Версия2[Разряд]);
		Если Результат <> 0 Тогда
			Возврат Результат;
		КонецЕсли;
	КонецЦикла;
	Возврат Результат;
	
КонецФункции

Функция ВерсияПоддерживается(ПоддерживаемыеВерсии, ПроверяемаяВерсия)
	
	Результат = Ложь;
	
	Для Каждого ПоддерживаемаяВерсия Из ПоддерживаемыеВерсии Цикл
		Если СравнитьВерсии(ПоддерживаемаяВерсия, ПроверяемаяВерсия) >= 0 Тогда
			Результат = Истина;
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

#КонецОбласти

#Область Прочее

Функция СтруктураНастроекXDTO() Экспорт
	
	Результат = Новый Структура;
	
	Результат.Вставить("Формат",                   "");
	Результат.Вставить("ПоддерживаемыеВерсии",     Новый Массив);
	Результат.Вставить("ПоддерживаемыеРасширения", Новый Соответствие);
	Результат.Вставить("ПоддерживаемыеОбъекты",    Новый ТаблицаЗначений);
	
	ИнициализироватьТаблицуПоддерживаемыхОбъектовФормата(Результат.ПоддерживаемыеОбъекты, "ОтправкаПолучение");
		
	Возврат Результат;
	
КонецФункции

// Разбирает строку на две части: до подстроки разделителя и после.
//
// Параметры:
//  Стр          - разбираемая строка;
//  Разделитель  - подстрока-разделитель:
//  Режим        - 0 - разделитель в возвращаемые подстроки не включается;
//                 1 - разделитель включается в левую подстроку;
//                 2 - разделитель включается в правую подстроку.
//
// Возвращаемое значение:
//  Правая часть строки - до символа-разделителя.
// 
Функция ОтделитьРазделителем(Стр, Знач Разделитель, Режим=0)

	ПраваяЧасть         = "";
	ПозРазделителя      = СтрНайти(Стр, Разделитель);
	ДлинаРазделителя    = СтрДлина(Разделитель);
	Если ПозРазделителя > 0 Тогда
		ПраваяЧасть	 = Сред(Стр, ПозРазделителя + ?(Режим=2, 0, ДлинаРазделителя));
		Стр          = СокрЛП(Лев(Стр, ПозРазделителя - ?(Режим=1, -ДлинаРазделителя + 1, 1)));
	КонецЕсли;

	Возврат(ПраваяЧасть);

КонецФункции

// Возвращает строковое представление типа, свойственного для данных,
// соответствующих переданному объекту метаданных.
// Может быть использован как значение параметра встроенной функции Тип().
//
// Параметры:
//  ОбъектМетаданных - ОбъектМетаданных - по которому необходимо определить имя типа;
//
// Возвращаемое значение:
//  Строка - например, "СправочникСсылка.Номенклатура".
//
Функция ИмяТипаДанныхПоОбъектуМетаданных(Знач ОбъектМетаданных)
	
	ЛитералыТипа = СтрРазделить(ОбъектМетаданных.ПолноеИмя(), ".");
	ТипТаблицы = ЛитералыТипа[0];
	
	Если ТипТаблицы = "Константа" Тогда
		
		ШаблонИмениТипа = "[ТипТаблицы]МенеджерЗначения.[ИмяТаблицы]";
		
	ИначеЕсли ТипТаблицы = "РегистрСведений"
		Или ТипТаблицы = "РегистрНакопления"
		Или ТипТаблицы = "РегистрБухгалтерии"
		Или ТипТаблицы = "РегистрРасчета" Тогда
		
		ШаблонИмениТипа = "[ТипТаблицы]НаборЗаписей.[ИмяТаблицы]";
		
	Иначе
		ШаблонИмениТипа = "[ТипТаблицы]Ссылка.[ИмяТаблицы]";
	КонецЕсли;
	
	ШаблонИмениТипа = СтрЗаменить(ШаблонИмениТипа, "[ТипТаблицы]", ЛитералыТипа[0]);
	Результат = СтрЗаменить(ШаблонИмениТипа, "[ИмяТаблицы]", ЛитералыТипа[1]);
	Возврат Результат;
	
КонецФункции

Процедура ЗаписатьПриНеобходимостиПубличныйИдентификатор(
		ДанныеДляЗаписиВИБ,
		ПолученныеДанныеСсылка,
		УИДСтрокой,
		ПравилоКонвертации,
		КомпонентыОбмена)
		
	УзелОбмена = КомпонентыОбмена.УзелКорреспондента;
	
	ВариантИдентификации = СокрЛП(ПравилоКонвертации.ВариантИдентификации);
	Если Не (ВариантИдентификации = "СначалаПоУникальномуИдентификаторуПотомПоПолямПоиска"
		Или ВариантИдентификации = "ПоУникальномуИдентификатору")
		Или Не ЗначениеЗаполнено(УзелОбмена) Тогда
		Возврат;
	КонецЕсли;
	
	СтруктураЗаписи = Новый Структура;
	СтруктураЗаписи.Вставить("УзелИнформационнойБазы", УзелОбмена);
	СтруктураЗаписи.Вставить("Ссылка", ?(ДанныеДляЗаписиВИБ = Неопределено, ПолученныеДанныеСсылка, ДанныеДляЗаписиВИБ.Ссылка));

	ИспользоватьКешПубличныхИдентификаторов = КомпонентыОбмена.ИспользоватьКешПубличныхИдентификаторов;
	
	Если НЕ ИспользоватьКешПубличныхИдентификаторов
		И ДанныеДляЗаписиВИБ <> Неопределено
		И РегистрыСведений.ПубличныеИдентификаторыСинхронизируемыхОбъектов.ЗаписьЕстьВРегистре(СтруктураЗаписи) Тогда
		
		Возврат;

	ИначеЕсли ИспользоватьКешПубличныхИдентификаторов
		И ДанныеДляЗаписиВИБ <> Неопределено
		И ЗаписьЕстьВКешеПубличныхИдентификаторов(СтруктураЗаписи, КомпонентыОбмена) Тогда
		
		Возврат;
		
	КонецЕсли;
		
	ПубличныйИдентификатор = ?(ЗначениеЗаполнено(УИДСтрокой), УИДСтрокой, ПолученныеДанныеСсылка.УникальныйИдентификатор());
	СтруктураЗаписи.Вставить("Идентификатор", ПубличныйИдентификатор);
		
	РегистрыСведений.ПубличныеИдентификаторыСинхронизируемыхОбъектов.ДобавитьЗапись(СтруктураЗаписи, Истина);
	
	ДобавитьЗаписьВКешПубличныхИдентификаторов(СтруктураЗаписи, КомпонентыОбмена);
	
КонецПроцедуры

Процедура ДобавитьВыгруженныеОбъектыВРегистрПубличныеИдентификаторы(КомпонентыОбмена)
	
	УзелДляОбмена = КомпонентыОбмена.УзелКорреспондента;
	СоставПланаОбмена = УзелДляОбмена.Метаданные().Состав;
	
	ШаблонТекстаЗапроса = 
	"ВЫБРАТЬ 
	|	ТаблицаИзменений.Ссылка
	|ИЗ 
	|	&ИмяТаблицыМетаданных КАК ТаблицаИзменений
	|ЛЕВОЕ СОЕДИНЕНИЕ 
	|	РегистрСведений.ПубличныеИдентификаторыСинхронизируемыхОбъектов КАК ПубличныеИдентификаторы
	|ПО ПубличныеИдентификаторы.УзелИнформационнойБазы = &Узел И ПубличныеИдентификаторы.Ссылка = ТаблицаИзменений.Ссылка
	|ГДЕ ТаблицаИзменений.Узел = &Узел И ТаблицаИзменений.НомерСообщения <= &НомерСообщения
	|	И ПубличныеИдентификаторы.Идентификатор ЕСТЬ NULL";
	
	Для Каждого ЭлементСостава Из СоставПланаОбмена Цикл
		
		Если НЕ ОбщегоНазначения.ЭтоОбъектСсылочногоТипа(ЭлементСостава.Метаданные) Тогда
			
			Продолжить;
			
		КонецЕсли;
		
		ИмяТаблицыМетаданных = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("%1.Изменения", ЭлементСостава.Метаданные.ПолноеИмя());
		ТекстЗапроса = СтрЗаменить(ШаблонТекстаЗапроса, "&ИмяТаблицыМетаданных", ИмяТаблицыМетаданных);
		
		Запрос = Новый Запрос(ТекстЗапроса);
		Запрос.УстановитьПараметр("Узел", УзелДляОбмена);
		Запрос.УстановитьПараметр("НомерСообщения", КомпонентыОбмена.НомерСообщенияПолученногоКорреспондентом);
		Выборка = Запрос.Выполнить().Выбрать();
		Пока Выборка.Следующий() Цикл
			
			СтруктураЗаписи = Новый Структура;
			СтруктураЗаписи.Вставить("Ссылка", Выборка.Ссылка);
			СтруктураЗаписи.Вставить("УзелИнформационнойБазы", КомпонентыОбмена.УзелКорреспондента);
			СтруктураЗаписи.Вставить("Идентификатор", Выборка.Ссылка.УникальныйИдентификатор());
			РегистрыСведений.ПубличныеИдентификаторыСинхронизируемыхОбъектов.ДобавитьЗапись(СтруктураЗаписи, Истина);
			
			ДобавитьЗаписьВКешПубличныхИдентификаторов(СтруктураЗаписи, КомпонентыОбмена);
			
		КонецЦикла;
		
	КонецЦикла;
	
КонецПроцедуры

Функция XMLБазоваяСхема()
	
	Возврат "http://www.1c.ru/SSL/Exchange/Message";
	
КонецФункции

Функция НомерВерсииСПоддержкойИдентификатораОбменаДанными()
	Возврат "1.5";
КонецФункции

Процедура ИнициализироватьТаблицуПоддерживаемыхОбъектовФормата(ТаблицаОбъекты, Режим)
	
	ТаблицаОбъекты.Колонки.Добавить("Версия", Новый ОписаниеТипов("Строка"));
	ТаблицаОбъекты.Колонки.Добавить("Объект", Новый ОписаниеТипов("Строка"));
	
	Если СтрНайти(Режим, "Отправка") Тогда
		ТаблицаОбъекты.Колонки.Добавить("Отправка", Новый ОписаниеТипов("Булево"));
	КонецЕсли;
	
	Если СтрНайти(Режим, "Получение") Тогда
		ТаблицаОбъекты.Колонки.Добавить("Получение", Новый ОписаниеТипов("Булево"));
	КонецЕсли;
	
	ТаблицаОбъекты.Индексы.Добавить("Версия, Объект");
	
КонецПроцедуры

Процедура ЗаполнитьПоддерживаемыеОбъектыФорматаПоКомпонентамОбмена(ТаблицаОбъекты, КомпонентыОбмена)
	
	Если КомпонентыОбмена.НаправлениеОбмена = "Отправка" Тогда
		
		Для Каждого ПравилоКонвертации Из КомпонентыОбмена.ПравилаКонвертацииОбъектов Цикл
			
			ТипОбъекта = ПравилоКонвертации.ТипXDTO; // ТипОбъектаXDTO
			
			Отбор = Новый Структура;
			Отбор.Вставить("Версия", КомпонентыОбмена.ВерсияФорматаОбмена);
			Отбор.Вставить("Объект", ТипОбъекта.Имя);
			
			СтрокиОбъекты = ТаблицаОбъекты.НайтиСтроки(Отбор);
			Если СтрокиОбъекты.Количество() = 0 Тогда
				СтрокаОбъекты = ТаблицаОбъекты.Добавить();
				ЗаполнитьЗначенияСвойств(СтрокаОбъекты, Отбор);
			Иначе
				СтрокаОбъекты = СтрокиОбъекты[0];
			КонецЕсли;
			
			СтрокаОбъекты.Отправка = Истина;
			
		КонецЦикла;
		
	ИначеЕсли КомпонентыОбмена.НаправлениеОбмена = "Получение" Тогда
		
		Для Каждого ПравилоОбработки Из КомпонентыОбмена.ПравилаОбработкиДанных Цикл
			
			Отбор = Новый Структура;
			Отбор.Вставить("Версия", КомпонентыОбмена.ВерсияФорматаОбмена);
			Отбор.Вставить("Объект", ПравилоОбработки.ОбъектВыборкиФормат);
			
			СтрокиОбъекты = ТаблицаОбъекты.НайтиСтроки(Отбор);
			Если СтрокиОбъекты.Количество() = 0 Тогда
				СтрокаОбъекты = ТаблицаОбъекты.Добавить();
				ЗаполнитьЗначенияСвойств(СтрокаОбъекты, Отбор);
			Иначе
				СтрокаОбъекты = СтрокиОбъекты[0];
			КонецЕсли;
			
			СтрокаОбъекты.Получение = Истина;
			
		КонецЦикла;
		
	КонецЕсли;
	
КонецПроцедуры

Функция ОбъектФорматаПроходитПоФильтруXDTO(КомпонентыОбмена, ОбъектФормата)
	
	Возврат Не КомпонентыОбмена.ЭтоОбменЧерезПланОбмена
		Или КомпонентыОбмена.ПоддерживаемыеОбъектыXDTO.Найти(ОбъектФормата) <> Неопределено;
	
КонецФункции
	
Функция ОбъектПроходитПоФильтруТаблицДляЗагрузки(ТаблицыДляЗагрузки, ТипДанныхПриОтправке, ТипДанныхПриПолучении)
	
	Если ТаблицыДляЗагрузки = Неопределено Тогда
		Возврат Истина;
	КонецЕсли;
	
	КлючТаблицыДанных = ОбменДаннымиСервер.КлючТаблицыДанных(ТипДанныхПриОтправке, ТипДанныхПриПолучении, Ложь);
	
	Возврат ТаблицыДляЗагрузки.Найти(КлючТаблицыДанных) <> Неопределено;
	
КонецФункции

Функция ПоискПоИдентификатору(Знач ВариантИдентификации)
	
	ВариантИдентификации = СокрЛП(ВариантИдентификации);
	
	Возврат (ВариантИдентификации = "СначалаПоУникальномуИдентификаторуПотомПоПолямПоиска")
		Или (ВариантИдентификации = "ПоУникальномуИдентификатору");
									
КонецФункции
	
Процедура ДополнитьСписокОбъектовКУдалению(КомпонентыОбмена, ТипДанных, УникальныйИдентификатор, МассивОбъектовКУдалению)
	
	СсылкаКУдалению = СсылкаОбъектаПоУИДОбъектаXDTO(УникальныйИдентификатор,
		ТипДанных, КомпонентыОбмена);
	Если МассивОбъектовКУдалению.Найти(СсылкаКУдалению) = Неопределено Тогда
		МассивОбъектовКУдалению.Добавить(СсылкаКУдалению);
	КонецЕсли;
	
КонецПроцедуры

Процедура ОбновитьСчетчикЗагруженныхОбъектов(КомпонентыОбмена)
	
	КомпонентыОбмена.СчетчикЗагруженныхОбъектов = КомпонентыОбмена.СчетчикЗагруженныхОбъектов + 1;
	ОбменДаннымиСервер.РассчитатьПроцентЗагрузки(КомпонентыОбмена.СчетчикЗагруженныхОбъектов,
		КомпонентыОбмена.КоличествоОбъектовКЗагрузке, КомпонентыОбмена.РазмерФайлаСообщенияОбмена);
	
КонецПроцедуры

// Параметры:
//   ТипОбъектаXDTO - ТипОбъектаXDTO
//   Свойства - Массив из Строка
// 
Процедура ЗаполнитьСписокСвойствОбъектаXDTO(ТипОбъектаXDTO, Свойства)
	
	Для Каждого ДочернееСвойство Из ТипОбъектаXDTO.Свойства Цикл
		Если ТипЗнч(ДочернееСвойство.Тип) = Тип("ТипОбъектаXDTO")
			И СтрНачинаетсяС(ДочернееСвойство.Тип.Имя, КлассОбщиеСвойства()) Тогда
			ЗаполнитьСписокСвойствОбъектаXDTO(ДочернееСвойство.Тип, Свойства);
		Иначе
			Свойства.Добавить(ДочернееСвойство.Имя);
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

Функция НайтиИмяПланаОбменаЧерезУниверсальныйФормат(КомпонентыОбмена, ПодтверждениеXDTO)

	Если КомпонентыОбмена.ОбменДаннымиСВнешнейСистемой Тогда
		Возврат ОбменДаннымиПовтИсп.ПолучитьИмяПланаОбмена(КомпонентыОбмена.УзелКорреспондента);
	КонецЕсли;
	
	Если ЗначениеЗаполнено(КомпонентыОбмена.УзелКорреспондента) Тогда
		
		Возврат ОбменДаннымиСервер.НайтиИмяПланаОбменаЧерезУниверсальныйФормат(ПодтверждениеXDTO.ExchangePlan);
		
	Иначе
		
		ИмяПланаОбмена = ТранслироватьИмя(ПодтверждениеXDTO.ExchangePlan, "en");
		ИмяПланаОбмена = Метаданные.ПланыОбмена.Найти(ИмяПланаОбмена);
		
	КонецЕсли;
	
КонецФункции

#КонецОбласти

#Область ТрансляцияФормата

Функция ТранслироватьИмя(ИсхдноеИмя, НаправлениеПеревода, ДоступныеИмена = Неопределено)
	
	Если Метаданные.ВариантВстроенногоЯзыка = Метаданные.СвойстваОбъектов.ВариантВстроенногоЯзыка.Русский Тогда
		Возврат ИсхдноеИмя;
	КонецЕсли;
	
	НовоеИмя = ОбменДаннымиТрансляцияФорматаПовтИсп.ТранслироватьИмя(ИсхдноеИмя, НаправлениеПеревода);
	
	Если ТипЗнч(НовоеИмя) = Тип("Строка") Тогда
		
		Возврат НовоеИмя;
		
	ИначеЕсли ДоступныеИмена <> Неопределено Тогда
		
		МассивДоступныхИмен = Новый Массив;
		
		Если ТипЗнч(ДоступныеИмена) = Тип("Структура") Тогда
			Для Каждого КлючИЗначение Из ДоступныеИмена Цикл
				МассивДоступныхИмен.Добавить(КлючИЗначение.Ключ);
			КонецЦикла;
		ИначеЕсли ТипЗнч(ДоступныеИмена) = Тип("ТипОбъектаXDTO") Тогда
			Для Каждого Свойство Из ДоступныеИмена.Свойства Цикл
				МассивДоступныхИмен.Добавить(Свойство.Имя);
			КонецЦикла;
		КонецЕсли;
		
		Для Каждого Имя Из НовоеИмя Цикл
			Если МассивДоступныхИмен.Найти(Имя) <> Неопределено Тогда
				Возврат Имя;
			КонецЕсли;
		КонецЦикла;
		
	Иначе
		
		Возврат НовоеИмя[0];
		
	КонецЕсли;
	
КонецФункции

Функция ТранслироватьПеречисление(Имя, НаправлениеПеревода, ТипXDTO)
	
	Если Метаданные.ВариантВстроенногоЯзыка = Метаданные.СвойстваОбъектов.ВариантВстроенногоЯзыка.Русский Тогда
		Возврат Имя;
	КонецЕсли;
	
	НовоеИмя = ОбменДаннымиТрансляцияФорматаПовтИсп.ТранслироватьИмя(Имя, НаправлениеПеревода);
	
	Если ТипЗнч(НовоеИмя) = Тип("Строка") Тогда
		
		Возврат НовоеИмя;
		
	Иначе
		
		Для Каждого Фасет Из ТипXDTO.Фасеты Цикл
			Если НовоеИмя.Найти(Фасет.Значение) <> Неопределено Тогда
				Возврат Фасет.Значение; 
				Прервать;
			КонецЕсли;
		КонецЦикла;
	
	КонецЕсли;
	
КонецФункции

Функция ТранслироватьСтруктуру(Источник, НаправлениеПеревода)
	
	Если Метаданные.ВариантВстроенногоЯзыка = Метаданные.СвойстваОбъектов.ВариантВстроенногоЯзыка.Русский Тогда
		Возврат Источник;
	КонецЕсли;
	
	Если ТипЗнч(Источник) = Тип("Структура") Тогда
		
		Результат = Новый Структура;
		
		Для Каждого КлючИЗначение Из Источник Цикл
			Ключ = ТранслироватьИмя(КлючИЗначение.Ключ, НаправлениеПеревода);
			Результат.Вставить(Ключ, ТранслироватьСтруктуру(КлючИЗначение.Значение, НаправлениеПеревода));
		КонецЦикла;
		
		Возврат Результат;
		
	ИначеЕсли ТипЗнч(Источник) = Тип("Массив") Тогда
		
		Результат = Новый Массив;
		
		Для Каждого ЭлМассива Из Источник Цикл
			Результат.Добавить(ТранслироватьСтруктуру(ЭлМассива, НаправлениеПеревода));
		КонецЦикла;
		
		Возврат Результат;
		
	ИначеЕсли ТипЗнч(Источник) = Тип("ТаблицаЗначений") Тогда
		
		Результат = Источник.Скопировать();
		
		ПерваяКолонка = Истина;
		
		Для Каждого Колонка Из Результат.Колонки Цикл
			
			Колонка.Имя = ТранслироватьИмя(Колонка.Имя, НаправлениеПеревода);
				
			Для Каждого Строка Из Результат Цикл
				Строка[Колонка.Имя] = ТранслироватьСтруктуру(Строка[Колонка.Имя], НаправлениеПеревода);
			КонецЦикла;
			
		КонецЦикла;
		
		Возврат Результат;
		
	Иначе
		
		Возврат Источник;
		
	КонецЕсли;
	
КонецФункции

Процедура ТранслироватьПредопределенныеДанные(ПравилаКонвертации)

	Если Метаданные.ВариантВстроенногоЯзыка = Метаданные.СвойстваОбъектов.ВариантВстроенногоЯзыка.Русский Тогда
		Возврат;
	КонецЕсли;
	
	Для Каждого Строка Из ПравилаКонвертации Цикл
		
		Если ЗначениеЗаполнено(Строка.КонвертацииЗначенийПриОтправке) Тогда
			
			ЗначенийПриОтправке = Новый Соответствие;
			
			Для Каждого КлючИЗначение Из Строка.КонвертацииЗначенийПриОтправке Цикл
				ЗначенийПриОтправке.Вставить(КлючИЗначение.Ключ, ТранслироватьИмя(КлючИЗначение.Значение, "ru"));
			КонецЦикла;
			
			Строка.КонвертацииЗначенийПриОтправке = ЗначенийПриОтправке;
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

#КонецОбласти

#Область КешПубличныхИдентификаторов

Процедура ЗаполнитьКешПубличныхИдентификаторов(КомпонентыОбмена, ИмяФайлаОбмена, ЧтениеXML)
	
	Если Не КомпонентыОбмена.ИспользоватьКешПубличныхИдентификаторов Тогда
		Возврат;
	КонецЕсли;
	
	ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
		
	ПостроительDOM = Новый ПостроительDOM;
	ДокументDOM = ПостроительDOM.Прочитать(КомпонентыОбмена.ФайлОбмена);
	
	// Получение формата обмена
	Разыменователь = Новый РазыменовательПространствИменDOM(ДокументDOM);
	Выражение = "//msg:Format";
	Результат = ДокументDOM.ВычислитьВыражениеXPath(Выражение, ДокументDOM, Разыменователь);
	
	УзелПоля = Результат.ПолучитьСледующий();
	Если УзелПоля = Неопределено Тогда
		Формат = "http://v8.1c.ru/edi/edi_stnd/EnterpriseData/" + КомпонентыОбмена.УзелКорреспондента.ВерсияФорматаОбмена;
	Иначе
		Формат = УзелПоля.ТекстовоеСодержимое;
	КонецЕсли;
	
	// Получение всех ссылок
	Разыменователь = Новый РазыменовательПространствИменDOM("ref", Формат);
	Выражение = "//ref:Ссылка";
	
	Результат = ДокументDOM.ВычислитьВыражениеXPath(Выражение, ДокументDOM, Разыменователь);
	
	КешСсылок = Новый ТаблицаЗначений;
	КешСсылок.Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("Строка",,,, Новый КвалификаторыСтроки(36)));
	
	Типы = Новый Массив();
	Типы.Добавить(ТипЗнч(КомпонентыОбмена.УзелКорреспондента));
	КешСсылок.Колонки.Добавить("УзелИнформационнойБазы", Новый ОписаниеТипов(Типы));
	
	Пока Истина Цикл
		
		УзелПоля = Результат.ПолучитьСледующий();
		Если УзелПоля = Неопределено Тогда
			Прервать;
		КонецЕсли;
		
		НоваяСтрока = КешСсылок.Добавить();
		НоваяСтрока.Идентификатор = УзелПоля.ТекстовоеСодержимое;
		НоваяСтрока.УзелИнформационнойБазы = КомпонентыОбмена.УзелКорреспондента;
		
	КонецЦикла;
	
	КешСсылок.Свернуть("Идентификатор, УзелИнформационнойБазы");
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	КешСсылок.Идентификатор КАК Идентификатор,
		|	КешСсылок.УзелИнформационнойБазы КАК УзелИнформационнойБазы
		|ПОМЕСТИТЬ КешСсылок
		|ИЗ
		|	&КешСсылок КАК КешСсылок
		|
		|ИНДЕКСИРОВАТЬ ПО
		|	Идентификатор,
		|	УзелИнформационнойБазы
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ
		|	Идентификаторы.Идентификатор КАК Идентификатор,
		|	Идентификаторы.Ссылка КАК Ссылка
		|ИЗ
		|	КешСсылок КАК КешСсылок
		|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ПубличныеИдентификаторыСинхронизируемыхОбъектов КАК Идентификаторы
		|		ПО КешСсылок.Идентификатор = Идентификаторы.Идентификатор
		|			И КешСсылок.УзелИнформационнойБазы = Идентификаторы.УзелИнформационнойБазы";
	
	Запрос.УстановитьПараметр("КешСсылок", КешСсылок);
	
	КешПубличныхИдентификаторов = Запрос.Выполнить().Выгрузить();
	КешПубличныхИдентификаторов.Индексы.Добавить("Идентификатор");
	КешПубличныхИдентификаторов.Индексы.Добавить("Ссылка");
	
	КомпонентыОбмена.КешПубличныхИдентификаторов = КешПубличныхИдентификаторов ;
	
	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.ОткрытьФайл(ИмяФайлаОбмена);
	КомпонентыОбмена.Вставить("ФайлОбмена", ЧтениеXML);
	
	ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
		ВремяНачала, "ПоискСсылок", "", КомпонентыОбмена, 
		ОбменДаннымиОценкаПроизводительности.ТипСобытияБиблиотека());
	
КонецПроцедуры

Процедура УдалитьЗаписьИзКешаПубличныхИдентификаторов(СтруктураЗаписи, КомпонентыОбмена)

	Если НЕ КомпонентыОбмена.ИспользоватьКешПубличныхИдентификаторов Тогда
		Возврат;
	КонецЕсли;
	
	СтруктураПоиска = Новый Структура();
	
	Если СтруктураЗаписи.Свойство("Ссылка") Тогда
		СтруктураПоиска.Вставить("Ссылка", СтруктураЗаписи.Ссылка);
	КонецЕсли;
	
	Если СтруктураЗаписи.Свойство("Идентификатор") Тогда
		СтруктураПоиска.Вставить("Идентификатор", СтруктураЗаписи.Идентификатор);
	КонецЕсли;
	
	КешПубличныхИдентификаторов = КомпонентыОбмена.КешПубличныхИдентификаторов;
	РезультатПоиска = КешПубличныхИдентификаторов.НайтиСтроки(СтруктураПоиска);
	
	Для Каждого Строка Из РезультатПоиска Цикл
		КешПубличныхИдентификаторов.Удалить(Строка);
	КонецЦикла;
	
КонецПроцедуры

Функция ЗаписьЕстьВКешеПубличныхИдентификаторов(СтруктураЗаписи, КомпонентыОбмена)
	
	СтруктураПоиска = Новый Структура();
	
	Если СтруктураЗаписи.Свойство("Ссылка") Тогда
		СтруктураПоиска.Вставить("Ссылка", СтруктураЗаписи.Ссылка);
	КонецЕсли;
	
	Если СтруктураЗаписи.Свойство("Идентификатор") Тогда
		СтруктураПоиска.Вставить("Идентификатор", СтруктураЗаписи.Идентификатор);
	КонецЕсли;
	
	РезультатПоиска = КомпонентыОбмена.КешПубличныхИдентификаторов.НайтиСтроки(СтруктураПоиска);
	
	Возврат РезультатПоиска.Количество() > 0; 
	
КонецФункции

Процедура ДобавитьЗаписьВКешПубличныхИдентификаторов(СтруктураЗаписи, КомпонентыОбмена)
	
	Если Не КомпонентыОбмена.ИспользоватьКешПубличныхИдентификаторов Тогда
		Возврат;
	КонецЕсли;
	
	ТипыСсылки = Метаданные.РегистрыСведений.ПубличныеИдентификаторыСинхронизируемыхОбъектов.Измерения.Ссылка.Тип;
	Если Не (ТипыСсылки.СодержитТип(ТипЗнч(СтруктураЗаписи.Ссылка))) Тогда
		Возврат;
	КонецЕсли;
	
	НоваяСтрока = КомпонентыОбмена.КешПубличныхИдентификаторов.Добавить();
	ЗаполнитьЗначенияСвойств(НоваяСтрока, СтруктураЗаписи);
		
КонецПроцедуры

#КонецОбласти

#Область РасширенияФорматаEnterpriseData

Функция ДоступныеРасширенияФормата(ВерсияФорматаОбмена) Экспорт
	
	Результат = Новый Соответствие;
	КоллекцияРасширений = Новый Соответствие;
	
	ОбменДаннымиПереопределяемый.ПриПолученииДоступныхРасширенийФормата(КоллекцияРасширений);
	
	СчетчикРасширений = 1;
	Для Каждого КлючЗначение Из КоллекцияРасширений Цикл
		
		Если ВерсияФорматаОбмена <> КлючЗначение.Значение Тогда
			
			Продолжить;
			
		КонецЕсли;
		
		Результат.Вставить(КлючЗначение.Ключ, СтрШаблон("ext%1", XMLСтрока(СчетчикРасширений)));
		СчетчикРасширений = СчетчикРасширений + 1;
		
	КонецЦикла;

	Возврат Результат;
	
КонецФункции

Функция ТипВложенногоСвойстваПоИмениИзРасширенияФормата(КомпонентыОбмена, ИмяБазовогоСвойства, ИмяРасширяемогоСвойства)
	
	РасширенноеСвойствоСтрокиТЧ = Неопределено;
	Для каждого ОписаниеРасширения Из КомпонентыОбмена.РасширенияФормата Цикл
		
		ТипИзРасширения = ФабрикаXDTO.Тип(ОписаниеРасширения.Ключ, ИмяБазовогоСвойства);
		Если ТипИзРасширения = Неопределено Тогда
			
			Продолжить;
			
		КонецЕсли;
		
		РасширенноеСвойствоСтрокиТЧ = ТипИзРасширения.Свойства.Получить(ИмяРасширяемогоСвойства);
		Прервать;
		
	КонецЦикла;
	
	Если РасширенноеСвойствоСтрокиТЧ <> Неопределено Тогда
		
		Возврат РасширенноеСвойствоСтрокиТЧ.Тип;
		
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

Процедура ДополнитьСвойстваПакетаИзРасширений(ТипXDTO, СвойстваИсточника, КомпонентыОбмена, Расширения)
	
	Если Расширения = Неопределено Тогда
		
		Возврат;
		
	КонецЕсли;
	
	// КомпонентыОбмена.РасширенияФормата - расширения из ОбменДаннымиПереопределяемый.ПриПолученииДоступныхРасширенийФормата();
	// Расширения - расширения инициализированное в правиле конвертации объекта.
	//
	// Концептуально можно было бы получать URI из КомпонентыОбмена.РасширенияФормата и проверять есть в нем объект формата ТипXDTO.Имя,
	// если есть, то обходить свойства в поисках новых (расширенных), но тогда этот алгоритм будет работать при выгрузке
	// всех объектов из-за чего будет потеря производительности.
	
	Для Каждого Расширение Из Расширения Цикл
		
		ПространствоИменРасширения = Расширение.Ключ;
		Если КомпонентыОбмена.РасширенияФормата.Получить(ПространствоИменРасширения) = Неопределено Тогда
			
			Продолжить;
			
		КонецЕсли;
		
		РасширенныйТипXDTO = ФабрикаXDTO.Тип(ПространствоИменРасширения, ТипXDTO.Имя);
		Если РасширенныйТипXDTO = Неопределено Тогда
			
			Продолжить;
			
		КонецЕсли;
		
		Для Каждого Свойство Из РасширенныйТипXDTO.Свойства Цикл
			
			Если Свойство.URIПространстваИмен <> ПространствоИменРасширения
				ИЛИ СвойстваИсточника.Найти(Свойство) <> Неопределено Тогда
				
				Продолжить;
				
			КонецЕсли;
			
			СвойстваИсточника.Добавить(Свойство);
			
		КонецЦикла;
		
	КонецЦикла;
	
КонецПроцедуры

Процедура ДополнитьКлючевыеСвойстваПакетаИзРасширений(ПравилоКонвертации, ТипКлючевыхСвойствОбъектаXDTO, МассивКлючевыхСвойств)
	
	Если ПравилоКонвертации.Расширения.Количество() < 1 Тогда
		
		Возврат;
		
	КонецЕсли;
	
	Для Каждого Расширение Из ПравилоКонвертации.Расширения Цикл
		
		РасширенныйТипОбъектаXDTO = ФабрикаXDTO.Тип(Расширение.Ключ, ТипКлючевыхСвойствОбъектаXDTO.Имя);
		Если РасширенныйТипОбъектаXDTO = Неопределено Тогда
			
			Продолжить;
			
		КонецЕсли;
		
		Для Каждого СвойствоИзРасширенияПакета Из РасширенныйТипОбъектаXDTO.Свойства Цикл
			
			Если Расширение.Ключ <> СвойствоИзРасширенияПакета.URIПространстваИмен
				ИЛИ МассивКлючевыхСвойств.Найти(СвойствоИзРасширенияПакета.Имя) <> Неопределено Тогда
				
				Продолжить;
				
			КонецЕсли;
			
			Если ТипЗнч(СвойствоИзРасширенияПакета.Тип) = Тип("ТипОбъектаXDTO")
				И СтрНачинаетсяС(СвойствоИзРасширенияПакета.Тип.Имя, КлассОбщиеСвойства()) Тогда
				
				ДополнитьКлючевыеСвойстваПакетаИзРасширений(ПравилоКонвертации, СвойствоИзРасширенияПакета.Тип, МассивКлючевыхСвойств);
				
			Иначе
				
				МассивКлючевыхСвойств.Добавить(СвойствоИзРасширенияПакета.Имя);
				
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЦикла;
	
КонецПроцедуры

Процедура ДополнитьТаблицуСвойствамиАктивныхРасширений(КомпонентыОбмена, ТипЗначенияXDTO, ЗначениеXDTO, Значение)
	
	Если НЕ ЭтоБазоваяСхема(КомпонентыОбмена, ТипЗначенияXDTO.URIПространстваИмен)
		ИЛИ КомпонентыОбмена.РасширенияФормата.Количество() = 0 Тогда
		
		Возврат;
		
	КонецЕсли;
	
	Для Каждого Расширение Из КомпонентыОбмена.РасширенияФормата Цикл
		
		РасширениеТипаЗначенияXDTO = ФабрикаXDTO.Тип(Расширение.Ключ, ТипЗначенияXDTO.Имя);
		Если РасширениеТипаЗначенияXDTO = Неопределено Тогда
			
			Продолжить;
			
		КонецЕсли;
		
		Для Каждого КлючевоеСвойство Из ЗначениеXDTO.Свойства() Цикл
			
			ОписаниеСвойства = РасширениеТипаЗначенияXDTO.Свойства.Получить(КлючевоеСвойство.Имя);
			Если ОписаниеСвойства = Неопределено Тогда
				
				Продолжить;
				
			КонецЕсли;
			
			КонвертацияСвойстваXDTOВЭлементСтруктуры(ЗначениеXDTO, КлючевоеСвойство, Значение, КомпонентыОбмена,,ОписаниеСвойства.Тип);
			
		КонецЦикла;
		
	КонецЦикла;
	
КонецПроцедуры

Процедура ПроверитьНаличиеОбщегоСвойстваВРасширениях(КомпонентыОбмена, ПодСвойство, ТипЗначенияXDTO, ОписаниеСвойства)
	
	Если ТипЗнч(КомпонентыОбмена.РасширенияФормата) <> Тип("Соответствие") Тогда
		
		Возврат;
		
	КонецЕсли;
	
	Для каждого РасширениеФормата Из КомпонентыОбмена.РасширенияФормата Цикл
		
		ПространствоИменРасширения = РасширениеФормата.Ключ;
		
		РасширенныйТипXDTO = ФабрикаXDTO.Тип(ПространствоИменРасширения, ТипЗначенияXDTO.Имя);
		Если РасширенныйТипXDTO = Неопределено Тогда
			
			Продолжить;
			
		КонецЕсли;
		
		ОписаниеСвойства = РасширенныйТипXDTO.Свойства.Получить(ПодСвойство.Имя);
		
	КонецЦикла;
	
КонецПроцедуры

Процедура РасширенияФорматаВКомпонентыОбмена(КомпонентыОбмена) Экспорт
	
	ДоступныеРасширенияФормата = ДоступныеРасширенияФормата(КомпонентыОбмена.ВерсияФорматаОбмена);
	Для Каждого РасширениеФорматаОбмена Из ДоступныеРасширенияФормата Цикл
		
		ВключитьПространствоИмен(КомпонентыОбмена,
			РасширениеФорматаОбмена.Ключ,
			РасширениеФорматаОбмена.Значение);
		
	КонецЦикла;
	
КонецПроцедуры

#КонецОбласти

#КонецОбласти
